ModSecurity (WAF) Configuration on Apache/Nginx
Introduction
Web Application Firewalls (WAFs) provide essential protection for web applications against common attacks including SQL injection, cross-site scripting (XSS), and many other OWASP Top 10 vulnerabilities. ModSecurity, an open-source WAF, has become the de facto standard for protecting web applications by monitoring, logging, and blocking malicious HTTP traffic before it reaches your application.
Originally designed for Apache, ModSecurity now supports Nginx through a dedicated connector, providing flexible deployment options across the most popular web servers. Combined with the OWASP Core Rule Set (CRS), ModSecurity offers comprehensive protection against a wide range of attacks while remaining highly customizable to meet specific application requirements.
This comprehensive guide covers ModSecurity installation, configuration, and optimization for both Apache and Nginx web servers. Whether you're protecting a simple website or a complex web application infrastructure, this guide provides the knowledge and practical techniques needed to implement effective web application security.
Understanding ModSecurity and Security Context
What Is ModSecurity?
ModSecurity is an open-source web application firewall (WAF) that operates as a module within web servers. It inspects HTTP(S) traffic in real-time, applying security rules to detect and prevent attacks before they reach your application.
How ModSecurity Works
ModSecurity operates through several key mechanisms:
1. Request Processing Phases
ModSecurity can inspect and intervene at five phases:
- Phase 1 (Request Headers): Inspects HTTP request headers
- Phase 2 (Request Body): Examines POST data, file uploads
- Phase 3 (Response Headers): Inspects response headers from application
- Phase 4 (Response Body): Examines HTML, JSON responses
- Phase 5 (Logging): Performs logging actions
2. Rule Engine
Rules define patterns to match and actions to take:
SecRule REQUEST_URI "@contains /admin" "id:1,phase:1,deny,status:403,msg:'Admin access denied'"
3. Detection Methods
- Pattern matching: Regular expressions and string matching
- Anomaly scoring: Assigns scores to suspicious patterns
- IP reputation: Blocks known malicious IPs
- Rate limiting: Prevents brute-force and DoS attacks
- Protocol validation: Enforces HTTP RFC compliance
4. Response Actions
- Block: Return error code (403, 404, etc.)
- Redirect: Send to different URL
- Log: Record for analysis
- Pass: Allow but log
- Drop: Silently drop connection
OWASP Core Rule Set (CRS)
The OWASP CRS is a collection of generic attack detection rules:
- Protects against OWASP Top 10 vulnerabilities
- Regular updates for new threats
- Minimal false positives with proper tuning
- Paranoia levels for security vs. compatibility balance
- Community-maintained and supported
Why ModSecurity Matters
ModSecurity provides critical web application protection:
- Prevents common attacks: SQL injection, XSS, CSRF, RCE
- Virtual patching: Protect vulnerable applications before patches available
- Compliance: Helps meet PCI DSS, HIPAA requirements
- Attack visibility: Detailed logging of attack attempts
- Defense in depth: Additional layer beyond application security
- Zero-day protection: Generic rules catch unknown exploits
- Reduces risk: Protects legacy applications
ModSecurity Deployment Modes
Detection Only (Monitoring)
- Rules detect but don't block
- Useful for tuning and testing
- Provides visibility without risk
Blocking (Protection)
- Rules actively block attacks
- Provides real security protection
- Requires proper tuning to avoid false positives
Reverse Proxy
- ModSecurity on separate server
- Protects multiple backend servers
- Centralized security management
Prerequisites
Before configuring ModSecurity, ensure you have:
System Requirements
- Operating System: Linux (Ubuntu, Debian, CentOS, RHEL)
- Web Server: Apache 2.4+ or Nginx 1.10+
- Memory: Minimum 512MB RAM (more for high traffic)
- CPU: Multi-core recommended for high traffic sites
- Disk Space: Adequate space for logs
Required Knowledge
- Web server administration (Apache or Nginx)
- Basic regular expressions
- HTTP protocol fundamentals
- Log analysis skills
- Application-specific knowledge for tuning
Software Requirements
For Apache on Ubuntu/Debian:
sudo apt-get update
sudo apt-get install libapache2-mod-security2
For Apache on CentOS/RHEL:
sudo yum install mod_security
For Nginx:
Nginx requires compilation with ModSecurity module (covered in installation steps).
Important Pre-Configuration Steps
- Backup configuration: Save current web server config
- Test environment: Have staging environment for testing
- Baseline traffic: Understand normal application traffic patterns
- Monitoring: Ensure log monitoring is in place
- Plan for tuning: Allocate time for false positive remediation
Step-by-Step ModSecurity Configuration
Step 1: Install ModSecurity for Apache
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install libapache2-mod-security2
Enable the module:
sudo a2enmod security2
sudo systemctl restart apache2
Verify installation:
apachectl -M | grep security
Should show: security2_module (shared)
CentOS/RHEL:
sudo yum install mod_security
sudo systemctl restart httpd
Step 2: Install ModSecurity for Nginx
Option 1: Install from Repository (if available)
sudo apt-get install libnginx-mod-security
Option 2: Compile Nginx with ModSecurity
This is more complex but provides latest versions:
Install dependencies:
sudo apt-get install git build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev \
libssl-dev libgd-dev libxml2 libxml2-dev uuid-dev
Download and compile ModSecurity library:
cd /opt
sudo git clone --depth 1 -b v3/master --single-branch https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
sudo git submodule init
sudo git submodule update
sudo ./build.sh
sudo ./configure
sudo make
sudo make install
Download ModSecurity-nginx connector:
cd /opt
sudo git clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git
Compile Nginx with ModSecurity:
cd /opt
sudo wget http://nginx.org/download/nginx-1.24.0.tar.gz
sudo tar -xzvf nginx-1.24.0.tar.gz
cd nginx-1.24.0
sudo ./configure --add-dynamic-module=../ModSecurity-nginx \
--with-http_ssl_module \
--with-http_v2_module
sudo make modules
sudo cp objs/ngx_http_modsecurity_module.so /usr/share/nginx/modules/
Load module in Nginx:
Add to /etc/nginx/nginx.conf (at the top):
load_module modules/ngx_http_modsecurity_module.so;
Step 3: Configure ModSecurity Basic Settings
For Apache:
Copy the recommended configuration:
sudo cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
For Nginx:
sudo mkdir -p /etc/nginx/modsec
sudo cp /opt/ModSecurity/modsecurity.conf-recommended /etc/nginx/modsec/modsecurity.conf
Edit the main configuration:
sudo nano /etc/modsecurity/modsecurity.conf # Apache
# or
sudo nano /etc/nginx/modsec/modsecurity.conf # Nginx
Key settings to configure:
# Enable ModSecurity (change from DetectionOnly to On)
SecRuleEngine On
# Request body access (needed to inspect POST data)
SecRequestBodyAccess On
# Maximum request body size (50MB)
SecRequestBodyLimit 52428800
# Response body access (inspect responses)
SecResponseBodyAccess On
# Response body MIME types to inspect
SecResponseBodyMimeType text/plain text/html text/xml application/json
# Directory for temporary files
SecTmpDir /tmp/
# Directory for persistent data
SecDataDir /var/cache/modsecurity
# Audit logging
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABIJDEFHZ
SecAuditLogType Serial
SecAuditLog /var/log/modsec_audit.log
# Debug logging (disable in production)
SecDebugLog /var/log/modsec_debug.log
SecDebugLogLevel 0
Step 4: Download and Install OWASP Core Rule Set (CRS)
Download CRS:
cd /opt
sudo git clone https://github.com/coreruleset/coreruleset.git
cd coreruleset
sudo git checkout v4.0/main
Install CRS:
For Apache:
sudo cp -r /opt/coreruleset/rules /etc/modsecurity/
sudo cp /opt/coreruleset/crs-setup.conf.example /etc/modsecurity/crs-setup.conf
For Nginx:
sudo cp -r /opt/coreruleset/rules /etc/nginx/modsec/
sudo cp /opt/coreruleset/crs-setup.conf.example /etc/nginx/modsec/crs-setup.conf
Step 5: Configure ModSecurity in Web Server
For Apache:
Create ModSecurity configuration file:
sudo nano /etc/apache2/mods-enabled/security2.conf
Add:
<IfModule security2_module>
SecDataDir /var/cache/modsecurity
IncludeOptional /etc/modsecurity/*.conf
IncludeOptional /etc/modsecurity/rules/*.conf
</IfModule>
Enable in VirtualHost:
sudo nano /etc/apache2/sites-available/000-default.conf
Add inside <VirtualHost>:
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
SecRuleEngine On
# Your other directives
</VirtualHost>
For Nginx:
Create main ModSecurity include file:
sudo nano /etc/nginx/modsec/main.conf
Add:
Include /etc/nginx/modsec/modsecurity.conf
Include /etc/nginx/modsec/crs-setup.conf
Include /etc/nginx/modsec/rules/*.conf
Enable in Nginx server block:
sudo nano /etc/nginx/sites-available/default
Add inside server block:
server {
listen 80;
server_name example.com;
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
location / {
root /var/www/html;
index index.html;
}
}
Step 6: Test Configuration
For Apache:
sudo apachectl configtest
sudo systemctl restart apache2
For Nginx:
sudo nginx -t
sudo systemctl restart nginx
Verify ModSecurity is working:
curl "http://localhost/?param=<script>alert(1)</script>"
Should be blocked with 403 Forbidden.
Check logs:
sudo tail -f /var/log/modsec_audit.log
Step 7: Set Anomaly Scoring Threshold
Edit CRS setup:
sudo nano /etc/modsecurity/crs-setup.conf # Apache
# or
sudo nano /etc/nginx/modsec/crs-setup.conf # Nginx
Configure paranoia level and thresholds:
# Paranoia Level (1-4, higher = more strict)
SecAction \
"id:900000,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=1"
# Inbound Anomaly Score Threshold
SecAction \
"id:900110,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.inbound_anomaly_score_threshold=5"
# Outbound Anomaly Score Threshold
SecAction \
"id:900111,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.outbound_anomaly_score_threshold=4"
Paranoia levels:
- Level 1: Basic protection, minimal false positives
- Level 2: Extended protection, some tuning needed
- Level 3: Strict protection, significant tuning required
- Level 4: Maximum protection, extensive tuning essential
Step 8: Create Custom Rules
Create custom rules file:
sudo nano /etc/modsecurity/rules/custom.conf # Apache
# or
sudo nano /etc/nginx/modsec/rules/custom.conf # Nginx
Example custom rules:
# Block specific user agents
SecRule REQUEST_HEADERS:User-Agent "@contains badbot" \
"id:1001,phase:1,deny,status:403,msg:'Bad bot blocked'"
# Rate limiting by IP
SecAction "id:1002,phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},\
setvar:ip.requests=+1,expirevar:ip.requests=60"
SecRule IP:REQUESTS "@gt 100" \
"id:1003,phase:1,deny,status:429,msg:'Rate limit exceeded'"
# Protect admin area
SecRule REQUEST_URI "@beginsWith /admin" \
"id:1004,phase:1,chain"
SecRule REMOTE_ADDR "!@ipMatch 192.168.1.0/24" \
"deny,status:403,msg:'Admin access from unauthorized IP'"
# Block SQL injection attempts in custom parameter
SecRule ARGS:search "@detectSQLi" \
"id:1005,phase:2,deny,status:403,log,msg:'SQL Injection Attempt in search'"
# Whitelist known IP
SecRule REMOTE_ADDR "@ipMatch 203.0.113.10" \
"id:1006,phase:1,pass,nolog,ctl:ruleEngine=Off"
Advanced ModSecurity Hardening Tips
1. Implement IP Reputation Lists
Use Project Honey Pot HTTP:BL:
SecRule REMOTE_ADDR "@ipMatchFromFile /etc/modsecurity/blacklist-ips.txt" \
"id:2001,phase:1,deny,status:403,msg:'IP Blacklisted'"
Update list regularly via cron:
0 2 * * * wget -O /etc/modsecurity/blacklist-ips.txt https://example.com/blacklist.txt
2. Implement Geolocation Blocking
Require GeoIP module and database:
sudo apt-get install libapache2-mod-geoip geoip-database
Block by country:
SecGeoLookupDB /usr/share/GeoIP/GeoIP.dat
SecRule REMOTE_ADDR "@geoLookup" "chain,id:2002,drop,msg:'Blocked by country'"
SecRule GEO:COUNTRY_CODE "@streq CN"
3. Implement Advanced Rate Limiting
Per-URI rate limiting:
SecAction "id:2003,phase:1,nolog,pass,\
initcol:ip=%{REMOTE_ADDR}_%{REQUEST_URI},\
setvar:ip.uri_requests=+1,\
expirevar:ip.uri_requests=10"
SecRule IP:URI_REQUESTS "@gt 20" \
"id:2004,phase:1,deny,status:429,\
msg:'Too many requests to specific URI'"
4. Implement Session Management
Track authenticated sessions:
SecRule REQUEST_COOKIES:sessionid "@rx ^[a-zA-Z0-9]{32}$" \
"id:2005,phase:1,pass,nolog,\
setvar:tx.session_valid=1"
SecRule TX:SESSION_VALID "!@eq 1" \
"id:2006,phase:1,deny,status:403,\
msg:'Invalid session ID format'"
5. Enable Response Header Filtering
Remove server information disclosure:
SecRule RESPONSE_HEADERS:Server "@rx (.*)" \
"id:2007,phase:3,pass,nolog,\
setvar:tx.server_header=%{MATCHED_VAR}"
Header always set Server "WebServer"
6. Implement Content Security Policy
Add CSP headers via ModSecurity:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
7. Create Application-Specific Rules
For WordPress:
# Block XML-RPC attacks
SecRule REQUEST_URI "@streq /xmlrpc.php" \
"id:3001,phase:1,deny,status:403,msg:'XML-RPC blocked'"
# Protect wp-login
SecRule REQUEST_URI "@beginsWith /wp-login.php" \
"id:3002,phase:1,chain"
SecRule &ARGS "@gt 3" \
"deny,status:403,msg:'Excessive login attempts'"
8. Implement Detailed Audit Logging
Configure comprehensive audit logging:
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogParts ABCDEFGHIJKZ
SecAuditLogType Concurrent
SecAuditLogStorageDir /var/log/modsec_audit/
SecAuditLogDirMode 0750
SecAuditLogFileMode 0640
Verification and Testing
Verify ModSecurity is Active
For Apache:
curl -I http://localhost
Look for Server header modifications or check error log:
sudo tail /var/log/apache2/error.log | grep ModSecurity
For Nginx:
sudo nginx -V 2>&1 | grep modsecurity
Test Basic Attack Detection
Test XSS detection:
curl "http://localhost/?test=<script>alert(1)</script>"
Should return 403 Forbidden.
Test SQL injection detection:
curl "http://localhost/?id=1' OR '1'='1"
Should be blocked.
Test path traversal:
curl "http://localhost/../../../../etc/passwd"
Should be blocked.
Monitor Audit Logs
Watch audit log in real-time:
sudo tail -f /var/log/modsec_audit.log
Search for specific attacks:
sudo grep "SQL Injection" /var/log/modsec_audit.log
Test False Positive Scenarios
Legitimate requests that might trigger false positives:
- Complex search queries
- URL parameters with special characters
- File uploads
- API POST requests with JSON
Document and whitelist as needed.
Performance Testing
Benchmark without ModSecurity:
ab -n 1000 -c 10 http://localhost/
Enable ModSecurity and benchmark again:
ab -n 1000 -c 10 http://localhost/
Compare results for performance impact.
Troubleshooting Common Issues
Issue 1: Too Many False Positives
Symptoms: Legitimate requests blocked
Solutions:
-
Identify the rule:
sudo grep "id" /var/log/modsec_audit.log | tail -20 -
Lower paranoia level: Reduce from level 2 to level 1 in crs-setup.conf
-
Whitelist specific rule for URI:
SecRuleRemoveById 942100 -
Create exception:
SecRule REQUEST_URI "@beginsWith /api/" \ "id:4001,phase:1,pass,nolog,ctl:ruleRemoveById=942100"
Issue 2: Performance Degradation
Symptoms: Slow response times after enabling ModSecurity
Solutions:
-
Disable response body inspection if not needed:
SecResponseBodyAccess Off -
Reduce request body limit:
SecRequestBodyLimit 10485760 -
Disable audit logging for normal requests:
SecAuditEngine RelevantOnly -
Use concurrent audit logging:
SecAuditLogType Concurrent
Issue 3: Configuration Errors
Symptoms: Web server won't start
Solutions:
-
Check syntax:
sudo apachectl configtest # Apache sudo nginx -t # Nginx -
Review error logs:
sudo tail -50 /var/log/apache2/error.log sudo tail -50 /var/log/nginx/error.log -
Common issues:
- Missing Include statements
- Incorrect file paths
- Duplicate rule IDs
- Syntax errors in custom rules
Issue 4: Rules Not Loading
Symptoms: Attacks not being blocked
Solutions:
-
Verify SecRuleEngine is On:
sudo grep "SecRuleEngine" /etc/modsecurity/modsecurity.conf -
Check Include statements: Ensure CRS rules are included
-
Verify file permissions:
sudo ls -la /etc/modsecurity/rules/ -
Test specific rule manually:
SecRule ARGS "@contains test" \ "id:9999,phase:2,deny,status:403,msg:'Test rule'"
Issue 5: Audit Log Filling Disk
Symptoms: Disk space exhausted
Solutions:
-
Use log rotation:
sudo nano /etc/logrotate.d/modsecurityAdd:
/var/log/modsec_audit.log { daily rotate 7 compress delaycompress notifempty create 640 www-data www-data postrotate systemctl reload apache2 > /dev/null endscript } -
Reduce audit logging:
SecAuditEngine RelevantOnly SecAuditLogRelevantStatus "^5"
Issue 6: JSON API Issues
Symptoms: JSON APIs being blocked incorrectly
Solutions:
-
Ensure JSON inspection is configured:
SecRule REQUEST_HEADERS:Content-Type "application/json" \ "id:4002,phase:1,pass,nolog,ctl:requestBodyProcessor=JSON" -
Whitelist API endpoints if necessary:
SecRule REQUEST_URI "@beginsWith /api/" \ "id:4003,phase:1,pass,nolog,ctl:ruleRemoveById=920000-920999"
Best Practices for ModSecurity Management
1. Deployment Strategy
- Start in DetectionOnly mode: Monitor without blocking initially
- Tune for your application: Spend time eliminating false positives
- Gradual rollout: Enable blocking on non-critical services first
- Have rollback plan: Be prepared to disable if issues arise
- Monitor continuously: Watch logs after enabling blocking
2. Rule Management
- Use CRS as baseline: Don't reinvent the wheel
- Keep CRS updated: Regular updates for new threats
- Document customizations: Maintain records of all custom rules
- Version control: Track changes to ModSecurity configuration
- Test before production: Always test rule changes in staging
3. Tuning Process
- Enable DetectionOnly mode
- Generate normal application traffic
- Review logs for false positives
- Create exceptions for legitimate traffic
- Enable blocking mode
- Monitor for new false positives
- Iterate and refine
4. Performance Optimization
- Disable unnecessary features: Turn off what you don't need
- Use concurrent audit logging: Better performance for high traffic
- Limit body inspection: Set reasonable size limits
- Optimize custom rules: Efficient regular expressions
- Consider hardware: More CPU/RAM for high-traffic sites
5. Security Hardening
- Use appropriate paranoia level: Balance security vs. usability
- Implement rate limiting: Prevent brute-force attacks
- Block known bad IPs: Use reputation lists
- Monitor for anomalies: Set up alerting for attack patterns
- Regular security audits: Review configuration quarterly
6. Logging and Monitoring
- Centralize logs: Send to SIEM or log aggregation platform
- Set up alerts: Notify on high-severity events
- Regular log review: Analyze attack patterns
- Compliance logging: Retain logs per regulatory requirements
- Performance metrics: Track ModSecurity overhead
7. Incident Response
- Document procedures: How to respond to attacks
- Emergency disablement: Know how to quickly disable if needed
- Attack analysis: Process for investigating blocked requests
- Rule updates: Procedure for implementing emergency rules
- Communication plan: Who to notify during incidents
Conclusion
ModSecurity provides robust, enterprise-grade web application firewall protection that defends against a wide range of attacks including OWASP Top 10 vulnerabilities. Combined with the OWASP Core Rule Set, ModSecurity offers comprehensive security that adapts to evolving threats through regular updates and community contributions.
Key takeaways:
- Essential protection: WAF layer critical for web application security
- Flexible deployment: Works with Apache and Nginx
- OWASP CRS: Provides mature, tested ruleset for common attacks
- Customizable: Adapt to specific application requirements
- Tuning required: Investment in tuning pays off in accurate protection
- Continuous monitoring: Ongoing management ensures effectiveness
ModSecurity is particularly valuable for:
- Protecting against OWASP Top 10 vulnerabilities
- Virtual patching of vulnerable applications
- Compliance with PCI DSS and other frameworks
- Gaining visibility into attack patterns
- Defense-in-depth security strategy
- Protecting legacy applications
Remember that ModSecurity is most effective when:
- Properly tuned to your application
- Regularly updated with latest rules
- Continuously monitored for alerts
- Part of comprehensive security strategy
- Backed by incident response procedures
Start with detection-only mode, invest time in proper tuning, and gradually enable blocking as confidence grows. With proper implementation and maintenance, ModSecurity becomes an invaluable security control that protects your web applications from a vast array of threats while providing detailed visibility into attack attempts. Combined with secure coding practices, regular vulnerability assessments, and comprehensive monitoring, ModSecurity forms a critical component of modern web application security.


