Web Application Firewalls
Last updated
Last updated
I still remember the day one of my client's e-commerce platforms was hit by a sophisticated SQL injection attack. As a freelance cloud architect at the time, I felt personally responsible. Despite having implemented a robust network firewall and conducting regular security audits, attackers found a vulnerability in one of the web forms. That incident was my wake-up call โ network security alone wasn't enough for modern web applications. That's when I dove deep into AWS Web Application Firewall (WAF), and it transformed how I approach application security for all my freelance projects.
When I first encountered AWS WAF, I thought of it as just another security product. I was wrong. AWS WAF is a Layer 7 (application layer) firewall specifically designed to protect web applications from sophisticated attacks that traditional network firewalls simply can't detect.
Think of traditional firewalls as security guards checking IDs at the building entrance โ they're great at controlling who gets in based on basic credentials. But AWS WAF is more like having a security expert who reads and understands every document being carried into the building, checking for hidden threats within the content itself.
After implementing AWS WAF across dozens of applications, I've come to see it as an essential shield that inspects every HTTP/HTTPS request before it even reaches your application, blocking malicious traffic based on patterns, signatures, and behaviors that you define.
In my implementations, I typically position AWS WAF in front of critical infrastructure like this:
This multi-layered approach has saved our applications countless times from being compromised.
The Open Web Application Security Project (OWASP) Top 10 represents the most critical security risks to web applications. When I first started with AWS WAF, configuring protection against all these threats seemed daunting. Then I discovered AWS Managed Rules.
AWS provides pre-configured rule groups specifically designed to address the OWASP Top 10 vulnerabilities. Here's how I typically set them up:
{
"Name": "OWASP-Protection",
"Priority": 0,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet",
"ExcludedRules": []
}
},
"OverrideAction": {
"None": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "OWASP-Protection"
}
}
For more specific OWASP protections, I layer on additional managed rule groups:
SQL Injection Protection: I use the AWSManagedRulesSQLiRuleSet
which has caught numerous attempts to inject malicious SQL into our form fields.
{
"Name": "SQLi-Protection",
"Priority": 10,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesSQLiRuleSet"
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "SQLi-Protection"
}
}
Cross-Site Scripting (XSS) Protection: The AWSManagedRulesXSSRuleSet
has been invaluable for detecting and blocking attempts to inject malicious scripts.
{
"Name": "XSS-Protection",
"Priority": 20,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesXSSRuleSet"
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "XSS-Protection"
}
}
One particularly clever attack I encountered was an XSS attempt hidden within a SVG upload that our WAF caught thanks to these rules.
Known Bad Inputs: I always include the AWSManagedRulesKnownBadInputsRuleSet
to catch requests that contain known suspicious patterns.
While managed rules provide excellent baseline protection, I've learned that custom rules are essential for addressing specific threats and business requirements. Here are some custom rules I've implemented that have made a significant difference:
After identifying a targeted attack from specific IP ranges, I quickly deployed this custom rule:
{
"Name": "Block-Malicious-IPs",
"Priority": 1,
"Action": {
"Block": {}
},
"Statement": {
"IPSetReferenceStatement": {
"ARN": "arn:aws:wafv2:us-east-1:123456789012:ipset/malicious-ips/abcdef12-3456-7890-abcd-ef1234567890"
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "BlockMaliciousIPs"
}
}
I maintain this IP set using AWS CLI, which allows me to quickly update it when our security team identifies new threat actors:
aws wafv2 update-ip-set \
--name malicious-ips \
--scope REGIONAL \
--id abcdef12-3456-7890-abcd-ef1234567890 \
--addresses 192.0.2.0/24 198.51.100.0/24 203.0.113.0/24
When we expanded into the EU market, data residency regulations required us to block access from certain regions. I implemented this geo-blocking rule:
{
"Name": "Geo-Restriction",
"Priority": 30,
"Action": {
"Block": {}
},
"Statement": {
"GeoMatchStatement": {
"CountryCodes": ["RU", "CN", "NK", "IR"]
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "GeoRestriction"
}
}
This single rule reduced our suspicious traffic alerts by over 70% while ensuring compliance with regional restrictions.
After noticing repeated login attempts on our authentication endpoints, I implemented a rate-limiting rule:
{
"Name": "Rate-Based-Rule",
"Priority": 40,
"Action": {
"Block": {}
},
"Statement": {
"RateBasedStatement": {
"Limit": 100,
"AggregateKeyType": "IP",
"ScopeDownStatement": {
"ByteMatchStatement": {
"SearchString": "/api/login",
"FieldToMatch": {
"UriPath": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "NONE"
}
],
"PositionalConstraint": "CONTAINS"
}
}
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateBasedRule"
}
}
This rule blocks any IP address making more than 100 requests to our login endpoint within five minutes, which effectively stopped brute force attempts without impacting legitimate users.
Some attackers use specific tools that identify themselves through their user agent strings. I created this rule to block known malicious crawlers and scanning tools:
{
"Name": "Block-Bad-Bots",
"Priority": 50,
"Action": {
"Block": {}
},
"Statement": {
"ByteMatchStatement": {
"SearchString": "nikto",
"FieldToMatch": {
"SingleHeader": {
"Name": "user-agent"
}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "LOWERCASE"
}
],
"PositionalConstraint": "CONTAINS"
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "BlockBadBots"
}
}
I extend this with an OR statement to include other known malicious user agents like sqlmap, dirbuster, and nessus.
When I deploy AWS WAF for a new application, I follow this proven process:
Start in Count Mode
I always begin by deploying rules in "Count" mode rather than "Block" mode:
aws wafv2 create-web-acl \
--name "MyApplicationWAF" \
--scope "REGIONAL" \
--default-action '{"Allow":{}}' \
--visibility-config '{
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "MyApplicationWAF"
}'
This approach lets me analyze traffic patterns and fine-tune rules before enforcing them.
Analyze Logs and Metrics
I set up logging to an S3 bucket and create CloudWatch dashboards to visualize request patterns:
aws wafv2 put-logging-configuration \
--resource-arn "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/MyApplicationWAF/abcdef12-3456-7890-abcd-ef1234567890" \
--logging-configuration '{
"ResourceArn": "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/MyApplicationWAF/abcdef12-3456-7890-abcd-ef1234567890",
"LogDestinationConfigs": ["arn:aws:s3:::waf-logs-bucket"]
}'
Gradually Transition to Block Mode
After a week of monitoring and fine-tuning, I transition rules to Block mode one by one, starting with the most confident rules (like SQL injection protection) and ending with more aggressive rules like rate limiting.
Since implementing AWS WAF across our applications, I've observed:
A 98% reduction in successful exploit attempts against our most critical applications
30% reduction in server load from filtering out malicious traffic early
Significantly improved response times for legitimate users
But it wasn't all smooth sailing. Here are some challenges I encountered:
False positives: Initially, some legitimate requests were blocked. I learned to carefully customize rule sensitivity and add exceptions for specific paths or parameters where needed.
Cost management: WAF pricing is based on the number of rules and requests. I optimized costs by focusing rules on our most critical endpoints rather than applying all rules to all traffic.
Mobile app compatibility: Some of our mobile app traffic was initially flagged as suspicious. I had to create custom rules to account for the unique signatures of our mobile clients.
In today's threat landscape, I consider AWS WAF as essential as having locks on your doors. The ability to inspect and filter HTTP traffic before it even reaches your application servers provides protection that no amount of application-level security coding can match.
What I appreciate most about AWS WAF is its adaptability. As new vulnerabilities emerge, I can quickly deploy new rulesโoften within minutes of a threat being identifiedโwithout having to modify any application code or redeploy services.
For any organization running public-facing web applications, especially those handling sensitive data or financial transactions, implementing a robust WAF solution like AWS WAF isn't just good practiceโin my experience, it's absolutely essential.
Through careful configuration of both managed and custom rules, you can create a security shield tailored to your specific application needs, blocking malicious traffic while ensuring a smooth experience for legitimate users.