A comparative analysis of three WAF approaches protecting DVWA (Damn Vulnerable Web Application):
- Unprotected - DVWA with no protection
- Open-Source WAF - OWASP ModSecurity CRS (nginx)
- Custom WAF - Python reverse proxy with regex-based detection
Browser --> :80 (DVWA direct - no protection)
Browser --> :8080 (ModSecurity CRS - open-source WAF)
Browser --> :9090 (Custom WAF - Python reverse proxy) --> :80 (DVWA)
cd Code-files
docker compose up -dThis starts:
- DVWA on
http://localhost(port 80) - ModSecurity CRS on
http://localhost:8080
Open a separate terminal:
cd Code-files
python waf.pyThe custom WAF starts on http://localhost:9090 and forwards clean traffic to DVWA.
- Go to
http://localhost - Click Create / Reset Database
- Login with
admin/password - Go to DVWA Security and set it to Low
| URL | Protection |
|---|---|
http://localhost |
None (unprotected) |
http://localhost:8080 |
ModSecurity CRS |
http://localhost:9090 |
Custom WAF |
- 33 detection rules across 7 attack categories:
- SQL Injection (10 rules)
- Cross-Site Scripting (9 rules)
- Path Traversal (3 rules)
- Command Injection (4 rules)
- SSRF (3 rules)
- Protocol Attacks (3 rules)
- LDAP Injection (1 rule)
- Multi-layer input normalization - recursive URL decoding, HTML entity decoding, null byte stripping
- Rate limiting - 100 requests/60s per IP with auto-block
- Response hardening - injects security headers (X-Frame-Options, X-Content-Type-Options, etc.)
- Cookie hardening - enforces HttpOnly and SameSite=Strict flags
- Server masking - hides backend server identity
- Structured JSON logging with unique incident IDs
With the WAF running, open another terminal:
cd Code-files
python test_&_analysis.pyThis runs 33 attack payloads and 10 legitimate requests against all three setups and produces a comparison report.
# Scan unprotected DVWA
docker run --rm --add-host=host.docker.internal:host-gateway alpine/nikto -h http://host.docker.internal:80
# Scan ModSecurity CRS
docker run --rm --add-host=host.docker.internal:host-gateway alpine/nikto -h http://host.docker.internal:8080
# Scan Custom WAF
docker run --rm --add-host=host.docker.internal:host-gateway alpine/nikto -h http://host.docker.internal:9090| Metric | Unprotected | ModSecurity CRS | Custom WAF |
|---|---|---|---|
| Block Rate | 0% (0/33) | 90.9% (30/33) | 100% (33/33) |
| False Positives | 0/10 | 0/10 | 0/10 |
| Nikto Issues | 7 | 7 | 2 |
WAF/
├── README.md
├── WAF Project.pdf # Project requirements
├── WAF_Final_Report_v2.docx # Final analysis report
├── Screenshots/ # Proof of concept screenshots
│ ├── database data leaked.png
│ ├── SQLi_blocked.png
│ ├── XSS_Attack_blocked.png
│ ├── SQLi_blocker_customWAF.png
│ ├── XSS_Attack_blocked_customWAF.png
│ ├── XSS_Proof.png
│ └── XSS.png
└── Code-files/
├── waf.py # Custom WAF source code
├── docker-compose.yml # DVWA + ModSecurity setup
├── test_&_analysis.py # Phase 4 comparison test suite
└── waf_blocked.log # WAF attack logs
# Stop Custom WAF
Ctrl+C in the WAF terminal
# Stop Docker containers
cd Code-files
docker compose down