diff --git a/owasp2nginx.py b/json2nginx.py
similarity index 70%
rename from owasp2nginx.py
rename to json2nginx.py
index c61058c..4bcd803 100644
--- a/owasp2nginx.py
+++ b/json2nginx.py
@@ -5,19 +5,23 @@ import logging
from pathlib import Path
from collections import defaultdict
+# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()],
)
+# Input and output paths
INPUT_FILE = Path(os.getenv("INPUT_FILE", "owasp_rules.json"))
OUTPUT_DIR = Path(os.getenv("OUTPUT_DIR", "waf_patterns/nginx"))
+# Create output directory if it doesn't exist
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
def load_owasp_rules(file_path):
+ """Load OWASP rules from a JSON file."""
try:
with open(file_path, "r") as f:
return json.load(f)
@@ -30,6 +34,7 @@ def load_owasp_rules(file_path):
def validate_regex(pattern):
+ """Validate if a pattern is a valid regex."""
try:
re.compile(pattern)
return True
@@ -38,7 +43,11 @@ def validate_regex(pattern):
def sanitize_pattern(pattern):
- if "@pmFromFile" in pattern or "!@eq" in pattern or "!@within" in pattern or "@lt" in pattern:
+ """Sanitize and validate OWASP patterns for Nginx compatibility."""
+ if any(
+ keyword in pattern
+ for keyword in ["@pmFromFile", "!@eq", "!@within", "@lt"]
+ ):
logging.warning(f"Skipping unsupported pattern: {pattern}")
return None
@@ -50,6 +59,7 @@ def sanitize_pattern(pattern):
def generate_nginx_waf(rules):
+ """Generate Nginx WAF configuration snippets from OWASP rules."""
categorized_rules = defaultdict(set)
# Group rules by category
@@ -69,13 +79,23 @@ def generate_nginx_waf(rules):
try:
with open(output_file, "w") as f:
f.write(f"# Nginx WAF rules for {category.upper()}\n")
+ f.write("# Automatically generated from OWASP rules.\n")
f.write("# Include this file in your server or location block.\n\n")
-
+
+ # Use a map to avoid redundant patterns
+ f.write("map $request_uri $waf_block_{category} {{\n".format(category=category))
+ f.write(" default 0;\n")
for pattern in patterns:
escaped_pattern = pattern.replace('"', '\\"')
- f.write(f'if ($request_uri ~* "{escaped_pattern}") {{\n')
- f.write(" return 403;\n")
- f.write("}\n\n")
+ f.write(f' "~*{escaped_pattern}" 1;\n')
+ f.write("}\n\n")
+
+ # Apply the WAF rule
+ f.write("if ($waf_block_{category}) {{\n".format(category=category))
+ f.write(" return 403;\n")
+ f.write(" # Log the blocked request (optional)\n")
+ f.write(" # access_log /var/log/nginx/waf_blocked.log;\n")
+ f.write("}\n\n")
logging.info(f"Generated {output_file} ({len(patterns)} patterns)")
except IOError as e:
@@ -99,9 +119,14 @@ def generate_nginx_waf(rules):
f.write(" ```bash\n")
f.write(" sudo nginx -t && sudo systemctl reload nginx\n")
f.write(" ```\n")
+ f.write("\n## Notes\n")
+ f.write("- The rules use `map` directives for efficient pattern matching.\n")
+ f.write("- Blocked requests return a `403 Forbidden` response by default.\n")
+ f.write("- You can enable logging for blocked requests by uncommenting the `access_log` line.\n")
def main():
+ """Main function to load rules and generate Nginx configurations."""
try:
logging.info("Loading OWASP rules...")
owasp_rules = load_owasp_rules(INPUT_FILE)
@@ -116,4 +141,4 @@ def main():
if __name__ == "__main__":
- main()
+ main()
\ No newline at end of file
diff --git a/owasp.py b/owasp2json.py
similarity index 100%
rename from owasp.py
rename to owasp2json.py
diff --git a/waf_patterns/nginx/README.md b/waf_patterns/nginx/README.md
index 8b13789..da8247d 100644
--- a/waf_patterns/nginx/README.md
+++ b/waf_patterns/nginx/README.md
@@ -1 +1,22 @@
+# Nginx WAF Rule Snippets
+This directory contains Nginx WAF rule snippets generated from OWASP rules.
+You can include these snippets in your existing Nginx configuration to enhance security.
+
+## Usage
+1. Include the rule snippets in your `server` or `location` block:
+ ```nginx
+ server {
+ # Your existing configuration
+ include /path/to/waf_patterns/nginx/*.conf;
+ }
+ ```
+2. Reload Nginx to apply the changes:
+ ```bash
+ sudo nginx -t && sudo systemctl reload nginx
+ ```
+
+## Notes
+- The rules use `map` directives for efficient pattern matching.
+- Blocked requests return a `403 Forbidden` response by default.
+- You can enable logging for blocked requests by uncommenting the `access_log` line.
diff --git a/waf_patterns/nginx/attack.conf b/waf_patterns/nginx/attack.conf
index 2063003..b91e387 100644
--- a/waf_patterns/nginx/attack.conf
+++ b/waf_patterns/nginx/attack.conf
@@ -1,64 +1,27 @@
# Nginx WAF rules for ATTACK
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "^[^sv,;]+[sv,;].*?(?:application/(?:.++)?json|(?:application/(?:soap+)?|text/)xml)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "TX:paramcounter_(.*)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "content-transfer-encoding:(.*)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "[rn]W*?(?:content-(?:type|length)|set-cookie|location):s*w") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt 0") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "(?:bhttp/d|<(?:html|meta)b)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^content-types*:s*(.*)$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "(?:get|post|head|options|connect|put|delete|trace|track|patch|propfind|propatch|mkcol|copy|move|lock|unlock)s+[^s]+s+http/d") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "[nr]") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "unix:[^|]*|") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "[nr]+(?:s|location|refresh|(?:set-)?cookie|(?:x-)?(?:forwarded-(?:for|host|server)|host|via|remote-ip|remote-addr|originating-IP))s*:") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^[^sv,;]+[sv,;].*?b(?:((?:tex|multipar)t|application)|((?:audi|vide)o|image|cs[sv]|(?:vn|relate)d|p(?:df|lain)|json|(?:soa|cs)p|x(?:ml|-www-form-urlencoded)|form-data|x-amf|(?:octe|repor)t|stream)|([+/]))b") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt 1") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* ".") {
- set $attack_detected 1;
- }
-
- if ($attack_detected = 1) {
- return 403;
- }
+map $request_uri $waf_block_attack {
+ default 0;
+ "~*^[^sv,;]+[sv,;].*?b(?:((?:tex|multipar)t|application)|((?:audi|vide)o|image|cs[sv]|(?:vn|relate)d|p(?:df|lain)|json|(?:soa|cs)p|x(?:ml|-www-form-urlencoded)|form-data|x-amf|(?:octe|repor)t|stream)|([+/]))b" 1;
+ "~*[nr]" 1;
+ "~*^content-types*:s*(.*)$" 1;
+ "~*content-transfer-encoding:(.*)" 1;
+ "~*(?:get|post|head|options|connect|put|delete|trace|track|patch|propfind|propatch|mkcol|copy|move|lock|unlock)s+[^s]+s+http/d" 1;
+ "~*@gt 1" 1;
+ "~*TX:paramcounter_(.*)" 1;
+ "~*@gt 0" 1;
+ "~*[rn]W*?(?:content-(?:type|length)|set-cookie|location):s*w" 1;
+ "~*[nr]+(?:s|location|refresh|(?:set-)?cookie|(?:x-)?(?:forwarded-(?:for|host|server)|host|via|remote-ip|remote-addr|originating-IP))s*:" 1;
+ "~*unix:[^|]*|" 1;
+ "~*." 1;
+ "~*(?:bhttp/d|<(?:html|meta)b)" 1;
}
+
+if ($waf_block_attack) {
+ return 403;
+ # Log the blocked request (optional)
+ # access_log /var/log/nginx/waf_blocked.log;
+}
+
diff --git a/waf_patterns/nginx/correlation.conf b/waf_patterns/nginx/correlation.conf
index 8a2492f..a4e26a9 100644
--- a/waf_patterns/nginx/correlation.conf
+++ b/waf_patterns/nginx/correlation.conf
@@ -1,28 +1,19 @@
# Nginx WAF rules for CORRELATION
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "@ge 5") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge %{tx.inbound_anomaly_score_threshold}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@eq 0") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt 0") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge %{tx.outbound_anomaly_score_threshold}") {
- set $attack_detected 1;
- }
-
- if ($attack_detected = 1) {
- return 403;
- }
+map $request_uri $waf_block_correlation {
+ default 0;
+ "~*@ge %{tx.outbound_anomaly_score_threshold}" 1;
+ "~*@ge %{tx.inbound_anomaly_score_threshold}" 1;
+ "~*@ge 5" 1;
+ "~*@gt 0" 1;
+ "~*@eq 0" 1;
}
+
+if ($waf_block_correlation) {
+ return 403;
+ # Log the blocked request (optional)
+ # access_log /var/log/nginx/waf_blocked.log;
+}
+
diff --git a/waf_patterns/nginx/enforcement.conf b/waf_patterns/nginx/enforcement.conf
index 4ff05fa..9b8e8ce 100644
--- a/waf_patterns/nginx/enforcement.conf
+++ b/waf_patterns/nginx/enforcement.conf
@@ -1,228 +1,73 @@
# Nginx WAF rules for ENFORCEMENT
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "(d+)-(d+)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^[^;s]+") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@contains #") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^bytes=(?:(?:d+)?-(?:d+)?s*,?s*){63}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@eq 1") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@validateByteRange 38,44-46,48-58,61,65-90,95,97-122") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@validateUtf8Encoding") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@streq POST") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt %{tx.max_file_size}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@rx ^(?:(?:max-age=[0-9]+|min-fresh=[0-9]+|no-cache|no-store|no-transform|only-if-cached|max-stale(?:=[0-9]+)?)(?:s*,s*|$)){1,7}$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "%[0-9a-fA-F]{2}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* ".[^.~]+~(?:/.*|)$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "x25") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@rx ^0?$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^(?:GET|HEAD)$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@validateByteRange 32-36,38-126") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "%u[fF]{2}[0-9a-fA-F]{2}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@rx ^OPTIONS$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@within %{tx.restricted_headers_basic}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "(?i)x5cu[0-9a-f]{4}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt %{tx.combined_file_sizes}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@endsWith .pdf") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@eq 0") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@rx ^0$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@pm AppleWebKit Android Business Enterprise Entreprise") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge 1") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@endsWith .pdf") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt 0") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@pm AppleWebKit Android") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@validateByteRange 1-255") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@within %{tx.restricted_extensions}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@rx ^(?:OPTIONS|CONNECT)$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "charsets*=s*[\"']?([^;\"'s]+)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@streq JSON") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "charset.*?charset") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^bytes=(?:(?:d+)?-(?:d+)?s*,?s*){6}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt 50") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt %{tx.total_arg_length}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@rx ^d+$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt 1") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt %{tx.arg_length}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "b(?:keep-alive|close),s?(?:keep-alive|close)b") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "['\";=]") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* ".([^.]+)$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt %{tx.max_num_args}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@within %{tx.restricted_headers_extended}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "(?:^|[^x5c])x5c[cdeghijklmpqwxyz123456789]") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@validateByteRange 32,34,38,42-59,61,65-90,95,97-122") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "(?:^([d.]+|[[da-f:]+]|[da-f:]+)(:[d]+)?$)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@gt %{tx.arg_name_length}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "!@rx ^[w/.+*-]+(?:s?;s?(?:action|boundary|charset|component|start(?:-info)?|type|version)s?=s?['\"w.()+,/:=?<>@#*-]+)*$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@validateByteRange 9,10,13,32-126,128-255") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^.*$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@validateUrlEncoding") {
- set $attack_detected 1;
- }
-
- if ($attack_detected = 1) {
- return 403;
- }
+map $request_uri $waf_block_enforcement {
+ default 0;
+ "~*!@rx ^[w/.+*-]+(?:s?;s?(?:action|boundary|charset|component|start(?:-info)?|type|version)s?=s?['\"w.()+,/:=?<>@#*-]+)*$" 1;
+ "~*!@rx ^(?:OPTIONS|CONNECT)$" 1;
+ "~*@eq 1" 1;
+ "~*.([^.]+)$" 1;
+ "~*@validateByteRange 38,44-46,48-58,61,65-90,95,97-122" 1;
+ "~*@gt %{tx.total_arg_length}" 1;
+ "~*!@streq JSON" 1;
+ "~*^(?:GET|HEAD)$" 1;
+ "~*@validateUtf8Encoding" 1;
+ "~*.[^.~]+~(?:/.*|)$" 1;
+ "~*@validateByteRange 32,34,38,42-59,61,65-90,95,97-122" 1;
+ "~*%u[fF]{2}[0-9a-fA-F]{2}" 1;
+ "~*!@pm AppleWebKit Android Business Enterprise Entreprise" 1;
+ "~*@gt %{tx.max_num_args}" 1;
+ "~*!@rx ^(?:(?:max-age=[0-9]+|min-fresh=[0-9]+|no-cache|no-store|no-transform|only-if-cached|max-stale(?:=[0-9]+)?)(?:s*,s*|$)){1,7}$" 1;
+ "~*^(?i)up" 1;
+ "~*!@pm AppleWebKit Android" 1;
+ "~*@streq POST" 1;
+ "~*^.*$" 1;
+ "~*!@rx ^d+$" 1;
+ "~*@validateUrlEncoding" 1;
+ "~*@gt %{tx.arg_length}" 1;
+ "~*@gt %{tx.combined_file_sizes}" 1;
+ "~*^bytes=(?:(?:d+)?-(?:d+)?s*,?s*){63}" 1;
+ "~*@ge 1" 1;
+ "~*@gt %{tx.arg_name_length}" 1;
+ "~*!@rx (?i)^(?:&(?:(?:[acegiln-or-suz]acut|[aeiou]grav|[ain-o]tild)e|[c-elnr-tz]caron|(?:[cgk-lnr-t]cedi|[aeiouy]um)l|[aceg-josuwy]circ|[au]ring|a(?:mp|pos)|nbsp|oslash);|[^\"';=])*$" 1;
+ "~*@gt 0" 1;
+ "~*b(?:keep-alive|close),s?(?:keep-alive|close)b" 1;
+ "~*@validateByteRange 32-36,38-126" 1;
+ "~*!@endsWith .pdf" 1;
+ "~*x25" 1;
+ "~*['\";=]" 1;
+ "~*^bytes=(?:(?:d+)?-(?:d+)?s*,?s*){6}" 1;
+ "~*@gt 50" 1;
+ "~*%[0-9a-fA-F]{2}" 1;
+ "~*charset.*?charset" 1;
+ "~*!@rx ^0?$" 1;
+ "~*!@rx ^OPTIONS$" 1;
+ "~*^(?i)multipart/form-data" 1;
+ "~*(?:^|[^x5c])x5c[cdeghijklmpqwxyz123456789]" 1;
+ "~*(?i)x5cu[0-9a-f]{4}" 1;
+ "~*charsets*=s*[\"']?([^;\"'s]+)" 1;
+ "~*@within %{tx.restricted_headers_extended}" 1;
+ "~*(?:^([d.]+|[[da-f:]+]|[da-f:]+)(:[d]+)?$)" 1;
+ "~*@gt %{tx.max_file_size}" 1;
+ "~*@endsWith .pdf" 1;
+ "~*@within %{tx.restricted_extensions}" 1;
+ "~*^$" 1;
+ "~*(d+)-(d+)" 1;
+ "~*@gt 1" 1;
+ "~*@validateByteRange 1-255" 1;
+ "~*@validateByteRange 9,10,13,32-126,128-255" 1;
+ "~*@within %{tx.restricted_headers_basic}" 1;
+ "~*^[^;s]+" 1;
+ "~*@eq 0" 1;
+ "~*@contains #" 1;
+ "~*!@rx ^0$" 1;
+ "~*^(?i)application/x-www-form-urlencoded" 1;
}
+
+if ($waf_block_enforcement) {
+ return 403;
+ # Log the blocked request (optional)
+ # access_log /var/log/nginx/waf_blocked.log;
+}
+
diff --git a/waf_patterns/nginx/evaluation.conf b/waf_patterns/nginx/evaluation.conf
index c717f69..91b725e 100644
--- a/waf_patterns/nginx/evaluation.conf
+++ b/waf_patterns/nginx/evaluation.conf
@@ -1,36 +1,21 @@
# Nginx WAF rules for EVALUATION
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "@ge 3") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge 4") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@eq 1") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge %{tx.inbound_anomaly_score_threshold}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge 1") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge 2") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ge %{tx.outbound_anomaly_score_threshold}") {
- set $attack_detected 1;
- }
-
- if ($attack_detected = 1) {
- return 403;
- }
+map $request_uri $waf_block_evaluation {
+ default 0;
+ "~*@ge 3" 1;
+ "~*@ge 4" 1;
+ "~*@eq 1" 1;
+ "~*@ge %{tx.outbound_anomaly_score_threshold}" 1;
+ "~*@ge %{tx.inbound_anomaly_score_threshold}" 1;
+ "~*@ge 1" 1;
+ "~*@ge 2" 1;
}
+
+if ($waf_block_evaluation) {
+ return 403;
+ # Log the blocked request (optional)
+ # access_log /var/log/nginx/waf_blocked.log;
+}
+
diff --git a/waf_patterns/nginx/exceptions.conf b/waf_patterns/nginx/exceptions.conf
index 179449d..6f8ea02 100644
--- a/waf_patterns/nginx/exceptions.conf
+++ b/waf_patterns/nginx/exceptions.conf
@@ -1,24 +1,18 @@
# Nginx WAF rules for EXCEPTIONS
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "@streq GET /") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@endsWith (internal dummy connection)") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@ipMatch 127.0.0.1,::1") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^(?:GET /|OPTIONS *) HTTP/[12].[01]$") {
- set $attack_detected 1;
- }
-
- if ($attack_detected = 1) {
- return 403;
- }
+map $request_uri $waf_block_exceptions {
+ default 0;
+ "~*^(?:GET /|OPTIONS *) HTTP/[12].[01]$" 1;
+ "~*@ipMatch 127.0.0.1,::1" 1;
+ "~*@streq GET /" 1;
+ "~*@endsWith (internal dummy connection)" 1;
}
+
+if ($waf_block_exceptions) {
+ return 403;
+ # Log the blocked request (optional)
+ # access_log /var/log/nginx/waf_blocked.log;
+}
+
diff --git a/waf_patterns/nginx/fixation.conf b/waf_patterns/nginx/fixation.conf
index 9fed171..d4d1c3f 100644
--- a/waf_patterns/nginx/fixation.conf
+++ b/waf_patterns/nginx/fixation.conf
@@ -1,28 +1,19 @@
# Nginx WAF rules for FIXATION
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "!@endsWith %{request_headers.host}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@eq 0") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^(?:ht|f)tps?://(.*?)/") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "^(?:jsessionid|aspsessionid|asp.net_sessionid|phpsession|phpsessid|weblogicsession|session_id|session-id|cfid|cftoken|cfsid|jservsession|jwsession)$") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "(?i:.cookieb.*?;W*?(?:expires|domain)W*?=|bhttp-equivW+set-cookieb)") {
- set $attack_detected 1;
- }
-
- if ($attack_detected = 1) {
- return 403;
- }
+map $request_uri $waf_block_fixation {
+ default 0;
+ "~*^(?:jsessionid|aspsessionid|asp.net_sessionid|phpsession|phpsessid|weblogicsession|session_id|session-id|cfid|cftoken|cfsid|jservsession|jwsession)$" 1;
+ "~*(?i:.cookieb.*?;W*?(?:expires|domain)W*?=|bhttp-equivW+set-cookieb)" 1;
+ "~*@eq 0" 1;
+ "~*!@endsWith %{request_headers.host}" 1;
+ "~*^(?:ht|f)tps?://(.*?)/" 1;
}
+
+if ($waf_block_fixation) {
+ return 403;
+ # Log the blocked request (optional)
+ # access_log /var/log/nginx/waf_blocked.log;
+}
+
diff --git a/waf_patterns/nginx/generic.conf b/waf_patterns/nginx/generic.conf
index 7680b87..33ad608 100644
--- a/waf_patterns/nginx/generic.conf
+++ b/waf_patterns/nginx/generic.conf
@@ -1,20 +1,17 @@
# Nginx WAF rules for GENERIC
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "[s*constructors*]") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "@{.*}") {
- set $attack_detected 1;
- }
-
- if ($request_uri ~* "while[sv]*([sv(]*(?:!+(?:false|null|undefined|NaN|[+-]?0|\"{2}|'{2}|`{2})|(?:!!)*(?:(?:t(?:rue|his)|[+-]?(?:Infinity|[1-9][0-9]*)|new [A-Za-z][0-9A-Z_a-z]*|window|String|(?:Boolea|Functio)n|Object|Array)b|{.*}|[.*]|\"[^\"]+\"|'[^']+'|`[^`]+`)).*)") {
- set $attack_detected 1;
- }
-
- if ($attack_detected = 1) {
- return 403;
- }
+map $request_uri $waf_block_generic {
+ default 0;
+ "~*while[sv]*([sv(]*(?:!+(?:false|null|undefined|NaN|[+-]?0|\"{2}|'{2}|`{2})|(?:!!)*(?:(?:t(?:rue|his)|[+-]?(?:Infinity|[1-9][0-9]*)|new [A-Za-z][0-9A-Z_a-z]*|window|String|(?:Boolea|Functio)n|Object|Array)b|{.*}|[.*]|\"[^\"]+\"|'[^']+'|`[^`]+`)).*)" 1;
+ "~*[s*constructors*]" 1;
+ "~*@{.*}" 1;
}
+
+if ($waf_block_generic) {
+ return 403;
+ # Log the blocked request (optional)
+ # access_log /var/log/nginx/waf_blocked.log;
+}
+
diff --git a/waf_patterns/nginx/iis.conf b/waf_patterns/nginx/iis.conf
index 0d5fdf7..95551ee 100644
--- a/waf_patterns/nginx/iis.conf
+++ b/waf_patterns/nginx/iis.conf
@@ -1,24 +1,18 @@
# Nginx WAF rules for IIS
-location / {
- set $attack_detected 0;
+# Automatically generated from OWASP rules.
+# Include this file in your server or location block.
- if ($request_uri ~* "(?:Microsoft OLE DB Provider for SQL Server(?:.{1,20}?error '800(?:04005|40e31)'.{1,40}?Timeout expired| (0x80040e31)
Timeout expired
)|