Implement WAF rules with LuaJIT - Demo and examples
Nginx WAF Rule LuaJIT Low Risk Version
Anti-CC Attack Rule
Filter Stage: Request Stage
Rule Description: If the frequency of accessing the /api/
path exceeds 360 times per minute, block the IP address from accessing for 5 minutes.
Rule Content:
if not waf.startWith(waf.toLower(waf.uri), "/api/") then
return false
end
local sh = ngx.shared.ipCache
local ccIp = 'cc-' .. waf.ip
local c, f = sh:get(ccIp)
if not c then
sh:set(ccIp, 1, 60, 1)
else
if f == 2 then
return waf.block(true)
end
sh:incr(ccIp, 1)
if c + 1 >= 360 then
sh:set(ccIp, c + 1, 300, 2)
return true, ccIp, true
end
end
return false
IIS Error Detection
Filter Stage: Return Page
Rule Description: IIS error pages may leak sensitive information about the server
Rule Content:
local rgx = waf.rgxMatch
local rb = waf.respBody
local m = rgx(rb, "[a-z]:\\x5cinetpub\\b", "jo")
if m then
return m, rb, true
end
if waf.status == 500 then
local m = rgx(rb, "Microsoft OLE DB Provider for SQL Server(?:</font>.{1,20}?error '800(?:04005|40e31)'.{1,40}?Timeout expired| \\(0x80040e31\\)<br>Timeout expired<br>)|<h1>internal server error</h1>.*?<h2>part of the server has crashed or it has a configuration error\\.</h2>|cannot connect to the server: timed out", "jo")
if m then
return m, rb, true
end
local m = rgx(rb, "\\b(?:A(?:DODB\\.Command\\b.{0,100}?\\b(?:Application uses a value of the wrong type for the current operation\\b|error')| trappable error occurred in an external object\\. The script cannot continue running\\b)|Microsoft VBScript (?:compilation (?:\\(0x8|error)|runtime (?:Error|\\(0x8))\\b|Object required: '|error '800)|<b>Version Information:</b>(?: |\\s)(?:Microsoft \\.NET Framework|ASP\\.NET) Version:|>error 'ASP\\b|An Error Has Occurred|>Syntax error in string in query expression|/[Ee]rror[Mm]essage\\.aspx?\\?[Ee]rror\\b", "jo")
if m then
return m, rb, true
end
end
if waf.status == 404 then
local m = rgx(rb, "\\bServer Error in.{0,50}?\\bApplication\\b", "jo")
if m then
return m, rb, true
end
end
return false
PHP Error Detection
Filtering Stage: Returning Page
Rule Description: PHP errors returned on a page may expose sensitive server information.
Rule Content:
local check = waf.plugins.phpErrorDetection.check
local rb = waf.respBody
if waf.status == 500 then
local m, d = check(rb)
if m then
return m, "php error: " .. d, true
end
end
return false
Java Error Detection
Filtering Phase: Returning Page
Rule Description: Java errors returned on a page may expose sensitive information about the server.
Rule Content:
local check = waf.plugins.javaErrorDetection.check
local rb = waf.respBody
if waf.status == 500 then
local m,d = check(rb)
if m then
return m, "Java error: " .. d, true
end
end
return false
Enhanced Request Methods
Filtering Stage: Request Stage
Rule Description: Uncommon HTTP request methods can lead to security vulnerabilities, such as the XSS-related vulnerability that occurred in the past with the TRACE request method on the Apache platform.
Rule Content:
if not waf.rgxMatch(waf.method, "^(?:GET|HEAD|POST|PUT|DELETE|OPTIONS)$") then
return true, waf.method, true
end
Nginx WAF Rule LuaJIT Moderate Risk Version
Robot Attack Protection
Filtering Stage: Request Stage
Rule Description: Intercept robot attacks such as vulnerability scanning, web scraping, and CC attacks through the generation of sliding rotation captchas. These automated attack behaviors have a token validity period of 30 minutes.
Rule Content:
local sh = ngx.shared.ipCache
local robotIp = 'rb:' .. waf.ip
local c, f = sh:get(robotIp)
if not (waf.isQueryString or waf.reqContentLength > 0) and f ~= 2 then
return false
end
if not c then
sh:set(robotIp, 1, 60, 1)
else
if f == 2 then
return waf.checkRobot(waf)
end
sh:incr(robotIp, 1)
if c + 1 >= 360 then
sh:set(robotIp, c + 1, 1800, 2)
return true, robotIp, true
end
end
return false
Weak Password Detection
Filtering Phase: Request Phase
Rule Description: Detect weak password issues in common login pages
Rule Content:
local check = waf.plugins.weakPwdDetection.check
local toLower = waf.toLower
local has = waf.contains
local form = waf.form
local uri = toLower(waf.uri)
if form and (has(uri, "login") or has(uri, "logon") or has(uri, "signin")) then
local f = form["FORM"]
if f then
for k, v in pairs(f) do
k = toLower(k)
if (k == "pass" or has(k, "pwd") or has(k, "passwd") or has(k, "password")) and check(v) then
return true, form["RAW"], false
end
end
end
end
return false
Sensitive File Leakage Detection
Filtering Stage: Request Stage
Rule Description: Detect various sensitive leaked file paths in URLs, such as svn, git, sql, log, bak, etc., to prevent exploitation by attackers.
Rule Content:
local m, d = waf.plugins.fileLeakDetection.check()
if m then
return true, d, true
end
return false
Request Body Size Limit
Filter Stage: Request Stage
Rule Description: Limit the size of the request body to below 8MB. Hackers may attempt to bypass WAF filtering with large data packets.
Rule Content:
if waf.reqContentLength>8388608 then
return true,"reqBody length is "..waf.reqContentLength ,true
end
return false
HTTP Parameter Pollution
Filtering Stage: Request Stage
Rule Description: HTTP parameter pollution attack. This rule looks for multiple parameters with the same name and checks for bypass issues that occur when weak validation of backend parameters is performed, such as foo[1]a=bar&foo[1]b=
or foo[1]x[1]=bar&foo[1]x[2]=
, etc.
Rule Content:
local rgx = waf.rgxMatch
local function rMatch(v)
local m = rgx(v, "(?:][^\\]]+$|][^\\]]+\\[)", "jos")
if m then
return m, v
end
return false
end
local form = waf.form
if form then
for k, v in pairs(form["FORM"]) do
if type(v) == "table" then
return true, k.."="..table.concat(v, ","), true
end
local m, d = rMatch(k)
if m then
return m, d, true
end
end
end
local queryString = waf.queryString
if queryString then
for k, v in pairs(queryString) do
if type(v) == "table" then
return true, k.."="..table.concat(v, ","), true
end
local m, d = rMatch(k)
if m then
return m, d, true
end
end
end
local cookies = waf.cookies
if cookies then
for k, v in pairs(cookies) do
if type(v) == "table" then
return true, k.."="..table.concat(v, ","), true
end
local m, d = rMatch(k)
if m then
return m, d, true
end
end
end
return false
Scanner Detection
Filtering Phase: Request Phase
Rule Description: Detect common scanners such as awvs, sqlmap, nessus, appscan, nmap, etc. Intercepting them helps reduce the risk of hackers discovering vulnerabilities.
Rule Content:
local m, d = waf.plugins.scannerDetection.check()
if m then
return true, d, true
end
return false
Nginx WAF Rule LuaJIT High Risk Version
SQL Error Detection
Filtering Stage: Returning Page
Rule Description: SQL errors returned on a page may leak sensitive server information
Rule Content:
local check = waf.plugins.sqlErrorDetection.check
local rb = waf.respBody
local rgx = waf.rgxMatch
local has = waf.contains
if waf.status == 500 then
local m = check(rb)
if m then
if rgx(rb, "JET Database Engine|Access Database Engine|\\[Microsoft\\]\\[ODBC Microsoft Access Driver\\]", "jo") then
return m, "Microsoft Access SQL Information Leakage: " .. rb, true
end
if rgx(rb, "ORA-[0-9][0-9][0-9][0-9]|java\\.sql\\.SQLException|Oracle error|Oracle.*Driver|Warning.*oci_.*|Warning.*ora_.*", "jo") then
return m, "Oracle SQL Information Leakage: " .. rb, true
end
if rgx(rb, "DB2 SQL error:|\\[IBM\\]\\[CLI Driver\\]\\[DB2/6000\\]|CLI Driver.*DB2|DB2 SQL error|db2_\\w+\\(", "jo") then
return m, "DB2 SQL Information Leakage: " .. rb, true
end
if rgx(rb, "\\[DM_QUERY_E_SYNTAX\\]|has occurred in the vicinity of:", "jo") then
return m, "EMC SQL Information Leakage: " .. rb, true
end
if has(rb, "Dynamic SQL Error") then
return m, "firebird SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Exception (?:condition )?\\d+\\. Transaction rollback\\.", "jo") then
return m, "Frontbase SQL Information Leakage: " .. rb, true
end
if has(rb, "org.hsqldb.jdbc") then
return m, "hsqldb SQL Information Leakage: " .. rb, true
end
if rgx(rb, "An illegal character has been found in the statement|com\\.informix\\.jdbc|Exception.*Informix", "jo") then
return m, "informix SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Warning.*ingres_|Ingres SQLSTATE|Ingres\\W.*Driver", "jo") then
return m, "ingres SQL Information Leakage: " .. rb, true
end
if rgx(rb, "<b>Warning</b>: ibase_|Unexpected end of command in statement", "jo") then
return m, "interbase SQL Information Leakage: " .. rb, true
end
if rgx(rb, "SQL error.*POS[0-9]+|Warning.*maxdb", "jo") then
return m, "maxDB SQL Information Leakage: " .. rb, true
end
if rgx(rb, "System\\.Data\\.OleDb\\.OleDbException|\\[Microsoft\\]\\[ODBC SQL Server Driver\\]|\\[Macromedia\\]\\[SQLServer JDBC Driver\\]|\\[SqlException|System\\.Data\\.SqlClient\\.SqlException|Unclosed quotation mark after the character string|'80040e14'|mssql_query\\(\\)|Microsoft OLE DB Provider for ODBC Drivers|Microsoft OLE DB Provider for SQL Server|Incorrect syntax near|Sintaxis incorrecta cerca de|Syntax error in string in query expression|Procedure or function .* expects parameter|Unclosed quotation mark before the character string|Syntax error .* in query expression|Data type mismatch in criteria expression\\.|ADODB\\.Field \\(0x800A0BCD\\)|the used select statements have different number of columns|OLE DB.*SQL Server|Warning.*mssql_.*|Driver.*SQL[ _-]*Server|SQL Server.*Driver|SQL Server.*[0-9a-fA-F]{8}|Exception.*\\WSystem\\.Data\\.SqlClient\\.", "jo") then
return m, "Mssql SQL Information Leakage: " .. rb, true
end
if rgx(rb, "MyS(?:QL server version for the right syntax to use|qlClient\\.)|(?:supplied argument is not a valid |SQL syntax.*)MySQL|Column count doesn't match(?: value count at row)?|(?:Table '[^']+' doesn't exis|valid MySQL resul)t|You have an error in your SQL syntax(?: near|;)|Warning.{1,10}mysql_(?:[a-z_()]{1,26})?|ERROR [0-9]{4} \\([a-z0-9]{5}\\):|mysql_fetch_array\\(\\)|on MySQL result index|\\[MySQL\\]\\[ODBC", "jo") then
return m, "Mysql SQL Information Leakage: " .. rb, true
end
if rgx(rb, "PostgreSQL query failed:|pg_query\\(\\) \\[:|pg_exec\\(\\) \\[:|PostgreSQL.{1,20}ERROR|Warning.*\\bpg_.*|valid PostgreSQL result|Npgsql\\.|PG::[a-zA-Z]*Error|Supplied argument is not a valid PostgreSQL .*? resource|Unable to connect to PostgreSQL server", "jo") then
return m, "Postgres SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Warning.*sqlite_|Warning.*SQLite3::|SQLite/JDBCDriver|SQLite\\.Exception|System\\.Data\\.SQLite\\.SQLiteException", "jo") then
return m, "SQLite SQL Information Leakage: " .. rb, true
end
if rgx(rb, "Sybase message:|Warning.{2,20}sybase|Sybase.*Server message", "jo") then
return m, "Sybase SQL Information Leakage: " .. rb, true
end
end
end
return false
Data Leakage Detection
Filtering Phase: Return Page
Rule Description: Detect directory traversal vulnerabilities and source code leakage issues from the returned page.
Rule Content:
local rgx = waf.rgxMatch
local rb = waf.respBody
local m = rgx(rb, "<(?:TITLE>Index of.*?<H|title>Index of.*?<h)1>Index of|>\\[To Parent Directory\\]</[Aa]><br>", "jo")
if m then
return m, "Directory Listing: " .. rb, true
end
m = rgx(rb, "^\\s*(?:#\\!\\s?/|<%|<\\?\\s*[^x]|<jsp:)", "jo")
if m then
return m, "Source code leak: " .. rb, true
end
return false
Session Fixation Attack
Filtering Stage: Request Stage
Rule Description: Session fixation attack is a method that takes advantage of an application system’s mechanism where the session ID remains unchanged on the server. By using the same session ID as someone else, an attacker can gain authentication and authorization, and then hijack the victim’s session to impersonate them, resulting in a session fixation attack.
Rule Content:
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local referer = waf.referer
local host = waf.host
local endWith = waf.endWith
local function sMatch(v)
local m = rgx(v, "\\bhttp-equiv\\W+set-cookie\\b", "joi")
if m then
return m, v
end
return false
end
local function nMatch(v)
local m = rgx(v, "^(?:jsessionid|aspsessionid|asp\\.net_sessionid|phpsession|phpsessid|weblogicsession|session_id|session-id|cfid|cftoken|cfsid|jservsession|jwsession)$", "joi")
if m then
return m, v
end
return false
end
local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
for k, v in pairs(form["FORM"]) do
m, d = nMatch(k)
if m then
if not referer then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
else
m = ngx.re.match(referer, "^https?://(.*?)/", "jo")
if m and not endWith(m[1], host) then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
end
end
end
end
end
local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
for k, v in pairs(queryString) do
m, d = nMatch(k)
if m then
if not referer then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
else
m = ngx.re.match(referer, "^https?://(.*?)/", "jo")
if m and not endWith(m[1], host) then
if type(v) == "table" then
v = table.concat(v)
end
return m, d .. ":" .. v, true
end
end
end
end
end
local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end
return false
Universal Attack
Filtering Phase: Request Phase
Rule Description: This rule intercepts Ruby, Node, JS, Perl injection, and SSRF attacks.
Rule Content:
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local function sMatch(v)
local m = rgx(v, "Process\\s*\\.\\s*spawn\\s*\\(", "jos")
if m then
return m, "Ruby Injection Attack: "..v
end
m = rgx(v, "t(?:his\\.constructor|runcateSync\\s*\\()|\\b(?:spawn|eval)\\s*\\(|_(?:\\$\\$ND_FUNC\\$\\$_|_js_function)|String\\s*\\.\\s*fromCharCode", "jos")
if m then
return m, "Node.js Injection Attack: "..v
end
m = rgx(v, "__proto__|constructor\\s*(?:\\.|\\[)\\s*prototype", "jos")
if m then
return m, "JavaScript Prototype Pollution: "..v
end
m = rgx(v, "(?:s(?:sh(?:2(?:.(?:s(?:(?:ft|c)p|hell)|tunnel|exec))?)?|m(?:[bs]|tps?)|vn(?:\\+ssh)?|n(?:ews|mp)|ips?|ftp|3)|p(?:op(?:3s?|2)|r(?:oxy|es)|h(?:ar|p)|aparazzi|syc)|c(?:ompress.(?:bzip2|zlib)|a(?:llto|p)|id|vs)|t(?:e(?:amspeak|lnet)|urns?|ftp)|f(?:i(?:nger|sh)|(?:ee)?d|tps?)|i(?:rc[6s]?|maps?|pps?|cap|ax)|d(?:a(?:ta|v)|n(?:tp|s)|ict)|m(?:a(?:ilto|ven)|umble|ms)|n(?:e(?:tdoc|ws)|ntps?|fs)|r(?:tm(?:f?p)?|sync|ar|mi)|v(?:iew-source|entrilo|nc)|a(?:ttachment|f[ps]|cap)|b(?:eshare|itcoin|lob)|g(?:o(?:pher)?|lob|it)|u(?:nreal|t2004|dp)|e(?:xpect|d2k)|h(?:ttps?|323)|w(?:ebcal|s?s)|ja(?:bbe)?r|x(?:mpp|ri)|ldap[is]?|ogg|zip):\\/\\/(?:(?:[\\d.]{0,11}(?:(?:\\xe2(?:\\x92(?:[\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4\\xb5]|[\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b]|[\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf]|[\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87])|\\x93(?:[\\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f]|[\\x9c\\x9d\\x9e\\x9f\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9]|[\\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\\x98\\x99\\x9a\\x9b]|[\\xbf\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe]|[\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3\\xb4])|\\x91(?:[\\xaa\\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\\xb0\\xb1\\xb2\\xb3]|[\\xb4\\xb5\\xb6\\xb7\\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf]))|\\xe3\\x80\\x82))+)|[a-z][\\w\\-\\.]{1,255}:\\d{1,5}(?:#?\\s*&?@(?:(?:\\d{1,3}\\.){3,3}\\d{1,3}|[a-z][\\w\\-\\.]{1,255}):\\d{1,5}\\/?)+|(?:0x[a-f0-9]{2}\\.){3}0x[a-f0-9]{2}|(?:0{1,4}\\d{1,3}\\.){3}0{1,4}\\d{1,3}|\\d{1,3}\\.(?:\\d{1,3}\\.\\d{5}|\\d{8})|0x(?:[a-f0-9]{16}|[a-f0-9]{8})|\\[[a-f\\d:]+(?:[\\d.]+|%\\w+)?\\]|(?:\\x5c\\x5c[a-z\\d-]\\.?_?)+|\\d{10})", "josi")
if m then
return m, "Possible Server Side Request Forgery (SSRF) Attack: "..v
end
m = rgx(v, "\\@\\{.*?\\}", "jos")
if m then
return m, "Perl Injection Attack: "..v
end
return false
end
local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
end
local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
end
local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end
local m, d = kvFilter(waf.reqHeaders, sMatch)
if m then
return m, d, true
end
return false
PHP Security Ruleset
Filtering Stage: Request Stage
Rule Description: Detects PHP-related vulnerabilities such as object serialization.
Rule Content:
local kvFilter = waf.kvFilter
local rgx = waf.rgxMatch
local function sMatch(v)
local m = rgx(v, "php://(?:std(?:in|out|err)|(?:in|out)put|fd|memory|temp|filter)|(?:ssh2(?:.(?:s(?:(?:ft|c)p|hell)|tunnel|exec))?|z(?:lib|ip)|(?:ph|r)ar|expect|bzip2|glob|ogg)://", "joi")
if m then
return m, v
end
m = rgx(v, "[oOcC]:\\d+:\"\\w+\":\\d+:{.*?}", "jos")
if m then
return m, v
end
return false
end
local function fileContentMatch(v)
local m = rgx(v, "<\\?.+?\\$_(?:GET|POST|COOKIE|REQUEST|SERVER|FILES|SESSION)|<\\?php", "jos")
if m then
return m, v
end
return false
end
local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], sMatch)
if m then
return m, d, true
end
m, d = waf.knFilter(form["FILES"], fileContentMatch, 0)
if m then
return m, d, true
end
end
local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, sMatch)
if m then
return m, d, true
end
end
local cookies = waf.cookies
if cookies then
local m, d = kvFilter(cookies, sMatch)
if m then
return m, d, true
end
end
local m, d = kvFilter(waf.reqHeaders, sMatch)
if m then
return m, d, true
end
return false
Path Traversal Attack
Filtering Phase: Request Phase
Rule Description: Detect path traversal attacks in URLs, uploaded files, or parameters. Using the LFI semantic detection engine, it can detect variations of attacks such as /////…\…\etc///passwd
.
Rule Content:
local checkPT = waf.checkPT
local kvFilter = waf.kvFilter
local function ptMatch(v)
local m = checkPT(v)
if m then
return m, v
end
return false
end
local url = waf.urlDecode(waf.reqUri)
if checkPT(url) then
return true, url, true
end
local form = waf.form
if form then
local m, d = kvFilter(form["FORM"], ptMatch)
if m then
return m, d, true
end
m, d = waf.knFilter(waf.form["FILES"], ptMatch, 1)
if m then
return m, d, true
end
end
local queryString = waf.queryString
if queryString then
local m, d = kvFilter(queryString, ptMatch)
if m then
return m, d, true
end
end
return false
Abnormal Request Character Encoding Interception
Filter Stage: Request Stage
Rule Description: Hackers typically use abnormal charset definitions in the Content-Type header to bypass WAF protection, such as IBM037, IBM500, cp875, etc.
Rule Content:
local rct = waf.reqContentType
local has = waf.contains
local counter = waf.strCounter
local rgx = waf.rgxMatch
if rct then
rct = waf.toLower(rct)
if has(rct, "charset") and (not rgx(rct, "charset\\s*=\\s*(utf\\-8|gbk|gb2312|iso\\-8859\\-1|iso\\-8859\\-15|windows\\-1252)","jo") or counter(rct, "charset") > 1) then
return true, rct, true
end
end
return false
Proxy Header SQL Injection
Filtering Stage: Request Stage
Rule Description: Filter single quote SQL injections in X-Forwarded-For and Client-IP request headers in HTTP requests.
local rip=waf.reqHeaders.x_forwarded_for
if rip then
if type(rip) ~= "string" then
return true,"Malform X-Forwarded-For",true
elseif waf.contains(rip,"'") then
return true,rip,true
end
end
rip=waf.reqHeaders.client_ip
if rip then
if type(rip) ~= "string" then
return true,"Malform Client-IP",true
elseif waf.contains(rip,"'") then
return true,rip,true
end
end
return false
Invalid protocol
Filter stage: Request stage
Rule description: Too many cookie parameters
Rule content:
if waf.cookies==nil then
return true,waf.cErr,true
end
return false
Invalid Protocol
Filter stage: Request stage
Rule description: Too many querystring parameters
Rule content:
if waf.cookies==nil then
return true,waf.cErr,true
end
return false
Reference
https://dusays.com/657/
https://dusays.com/658/
https://dusays.com/659/