So far in our WAF journey, we’ve covered the fundamentals of WAF configurations and explored the different processing phases. But if you’ve worked with WAF in production environments, you’ve likely encountered the infamous problem: false positives.
I still remember deploying a seemingly perfect WAF configuration only to be bombarded with alerts from the operations team because legitimate traffic was being blocked. One time, a marketing campaign launched and suddenly our WAF was blocking thousands of valid requests because the URL contained a string that matched a SQL injection pattern. Not fun.
This brings us to our topic today: tuning WAF rules for precision using variables and exclusions.
The Challenge: Balancing Security and Usability
Out-of-the-box WAF configurations like OWASP CRS are designed to catch a wide range of attacks, but this broad coverage comes at a cost - they don’t know your specific application and will often flag legitimate traffic as malicious.
It’s like having an overly suspicious security guard who stops everyone wearing a hoodie. Sure, you might catch some troublemakers, but you’ll also inconvenience many legitimate visitors.
Understanding WAF Variables for Precision Tuning
To tune WAF effectively, we need to understand the variables we can use to target specific parts of HTTP transactions. These variables act like filters that allow us to examine only the relevant parts of requests and responses.
Common WAF Variables for Tuning
Variable | Description | Example Use Case |
---|---|---|
ARGS | All arguments/parameters (GET and POST combined) | Check all parameters for SQL injection |
ARGS_GET | Only GET query parameters | Filter parameters in the URL |
ARGS_POST | Only POST parameters | Check form submissions |
ARGS_NAMES | Names of all parameters | Block suspicious parameter names |
REQUEST_COOKIES | Values of all cookies | Check for session tampering |
REQUEST_COOKIES_NAMES | Names of all cookies | Identify rogue cookies |
REQUEST_HEADERS | All HTTP request headers | Detect header-based attacks |
REQUEST_HEADERS_NAMES | Names of request headers | Block unusual headers |
REQUEST_URI | The URI path | Block access to sensitive paths |
REQUEST_FILENAME | The filename part of the URI | Block access to specific file types |
TX | Transaction variables (internal to ModSecurity) | Store and use custom values |
Targeting Specific Variables
Instead of applying rules to everything, we can target specific parts of the request. Compare these two approaches:
# Broad check (more likely to cause false positives)
SecRule ARGS "@rx select\s+.+\s+from" \
"id:1000,phase:2,deny,msg:'Generic SQL Injection'"
# Targeted check (more precise)
SecRule ARGS:username "@rx select\s+.+\s+from" \
"id:1001,phase:2,deny,msg:'SQL Injection in username parameter'"
The second rule only checks the “username” parameter, reducing the chance of false positives in other fields where SQL-like syntax might be legitimate.
Practical Tuning Techniques
Now that we understand the variables we can use, let’s look at practical techniques for tuning WAF rules.
1. Excluding Specific Parameters
Some parameters in your application might legitimately contain patterns that look like attacks. For example, a rich text editor might allow HTML tags that look like XSS attacks.
# Exclude the 'content' parameter from XSS checks
SecRuleUpdateTargetById 941100 "!ARGS:content"
This rule tells ModSecurity to not apply rule ID 941100 (an XSS detection rule) to the ‘content’ parameter.
2. Excluding Specific Paths
Some application paths might need different security rules. For instance, an admin area might legitimately use SQL-like syntax in parameters.
# Exclude admin area from SQL injection rules
SecRule REQUEST_URI "@beginsWith /admin/" \
"id:2000,phase:1,pass,nolog,ctl:ruleRemoveTargetById=942100;ARGS"
This rule disables SQL injection checks (rule 942100) for all parameters when the request path starts with “/admin/”.
3. Excluding Specific IP Addresses
Sometimes you need to whitelist trusted sources like monitoring systems or internal tools.
# Whitelist internal monitoring system
SecRule REMOTE_ADDR "@ipMatch 192.168.1.5" \
"id:3000,phase:1,pass,nolog,ctl:ruleEngine=Off"
This completely disables ModSecurity for requests coming from the IP 192.168.1.5.
NOTE: However this might be handled at network devices via ACLs, be aware that WAF has the capability of acting on IP addresses.
4. Creating Custom Rules for Application Logic
Sometimes generic rules aren’t enough - you need rules that understand your application’s specific logic.
# Ensure 'action' parameter only contains allowed values
SecRule ARGS:action "!@within view,edit,delete" \
"id:4000,phase:2,deny,status:403,msg:'Invalid action parameter'"
This rule will only allow ‘view’, ‘edit’, or ‘delete’ as values for the ‘action’ parameter.
Real-World Example: Tuning a File Upload Form
Let’s say your application has a file upload form that triggers WAF protections. Here’s how we might tune it:
# Allow necessary content types for file uploads
SecRule REQUEST_URI "@beginsWith /upload.php" \
"id:5000,phase:1,pass,nolog,ctl:ruleRemoveTargetById=920420;REQUEST_HEADERS:Content-Type"
# Skip multipart parsing errors for upload form
SecRule REQUEST_URI "@beginsWith /upload.php" \
"id:5001,phase:1,pass,nolog,ctl:ruleRemoveById=920440"
# Allow larger file size but only for upload endpoint
SecRule REQUEST_URI "@beginsWith /upload.php" \
"id:5002,phase:1,pass,nolog,ctl:requestBodyLimit=10485760"
These rules create exceptions for our upload form while maintaining protection elsewhere.
The Tuning Process: Methodology Over Madness
Tuning a WAF is not a one-time task but an iterative process. Here’s a methodical approach:
-
Start in Detection-Only Mode: Begin with WAF in logging mode (SecRuleEngine DetectionOnly) to identify false positives without blocking traffic.
-
Analyze WAF Logs: Look for patterns of legitimate requests being flagged.
-
Group False Positives: Categorize them by rule IDs, URLs, parameters, or IP addresses.
-
Create Targeted Exclusions: Address each category with the most precise exclusion possible.
-
Test and Verify: Ensure your exclusions work as expected and don’t create security gaps.
-
Document Everything: Keep detailed records of what you’ve excluded and why.
-
Periodically Review: Security needs change as applications evolve.
Best Practices for WAF Tuning
- Be as Specific as Possible:
- Target specific parameters instead of disabling entire rule categories
- Limit exclusions to specific URLs or IP ranges when possible
- Use Detection Only Mode During Initial Tuning:
SecRuleEngine DetectionOnly # Log but don't block
- Increment Custom Rule IDs Logically:
- Use a consistent numbering scheme (e.g., 10000-19999 for custom rules)
- Group related rules together
- Comment Your Tuning Rules:
# BEGIN WHITELIST FOR MARKETING CAMPAIGN (Expires: 2025-03-01) # This rule whitelists the special URL parameter used in our Q1 campaign SecRuleUpdateTargetById 942100 "!ARGS:campaign_2025q1" # END WHITELIST
- Set Expiration Dates for Temporary Exclusions:
- Document when temporary exclusions should be removed
- Regular review prevents security creep
- Use Variable Collections Wisely:
- MATCHED_VARS is more efficient than checking individual variables
- REQUEST_FILENAME is better than parsing REQUEST_URI for file checks
Advanced Tuning with ModSecurity Variables
For more complex scenarios, you can use ModSecurity’s transaction variables (TX) to create sophisticated logic:
# Set a transaction variable based on a condition
SecRule REQUEST_URI "@rx ^/api/v1/" \
"id:6000,phase:1,pass,setvar:tx.is_api_request=1"
# Use the transaction variable in another rule
SecRule TX:is_api_request "@eq 1" \
"id:6001,phase:2,pass,ctl:ruleRemoveById=941100"
This example disables XSS protection (rule 941100) but only for requests to the API endpoint.
Conclusion
WAF tuning is as much an art as it is a science. It requires understanding your application, the attacks it might face, and finding the delicate balance between security and functionality.
Remember, the goal isn’t to disable security - it’s to make it smarter. Every exclusion should be as narrowly targeted as possible to maintain protection while eliminating false positives.
In my experience, a well-tuned WAF becomes invisible to legitimate users while remaining a formidable barrier to attackers. It takes time and patience to reach this sweet spot, but the result is worth it: robust security that doesn’t get in the way of your business.
In the next article, we’ll dive into performance tuning for WAF, exploring the differences between operators like @rx and @pm to ensure your security doesn’t come at the cost of speed. Stay tuned!
Photo by Alexis Baydoun on Unsplash