WAF Fundamentals
WAF Fundamentals
AWS WAF is a web application firewall that protects against common web exploits and bots.
WAF Components
| Component | Description |
|---|---|
| Web ACL | Collection of rules |
| Rules | Conditions that trigger actions |
| Rule Group | Reusable set of rules |
| Action | Allow, Block, or Count |
Create Web ACL
# Create a web ACL
aws wafv2 create-web-acl \
--name my-web-acl \
--scope REGIONAL \
--default-action '{"Allow": {}}' \
--rules '[{
"Name": "RateLimitRule",
"Priority": 1,
"Statement": {
"RateBasedStatement": {
"Limit": 2000,
"AggregateKeyType": "IP"
}
},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateLimitRule"
}
}]' \
--visibility-config '{
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "my-web-acl"
}' \
--association-configuration '{
"RequestBodyConfig": {
"InspectionSize": 8192
}
}'
Attach to ALB
# Associate WAF with ALB
aws wafv2 associate-web-acl \
--web-acl-arn arn:aws:wafv2:us-east-1:xxx:regional/webacl/my-web-acl/xxx \
--resource-arn arn:aws:elasticloadbalancing:us-east-1:xxx:loadbalancer/app/my-alb/xxx
WAF Rules and Conditions
WAF Rules and Conditions
Rate-Based Rules
# Block IPs making more than 100 requests per 5 minutes
aws wafv2 create-web-acl \
--name rate-limiting \
--scope REGIONAL \
--default-action '{"Allow": {}}' \
--rules '[{
"Name": "RateLimit",
"Priority": 1,
"Statement": {
"RateBasedStatement": {
"Limit": 100,
"AggregateKeyType": "IP"
}
},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateLimit"
}
}]'
IP Set Filtering
# Create IP set
aws wafv2 create-ip-set \
--name blocked-ips \
--scope REGIONAL \
--addresses '203.0.113.0/24,198.51.100.1'
# Create rule using IP set
aws wafv2 create-web-acl \
--name ip-filtering \
--scope REGIONAL \
--default-action '{"Allow": {}}' \
--rules '[{
"Name": "BlockBadIPs",
"Priority": 1,
"Statement": {
"IPSetReferenceStatement": {
"ARN": "arn:aws:wafv2:us-east-1:xxx:regional/ipset/blocked-ips/xxx"
}
},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "BlockBadIPs"
}
}]'
SQL Injection Protection
# Add SQL injection rule
aws wafv2 update-web-acl \
--name my-web-acl \
--scope REGIONAL \
--lock-token lock-token \
--rules '[{
"Name": "SQLInjection",
"Priority": 2,
"Statement": {
"SqliMatchStatement": {
"FieldToMatch": {
"Body": {
"OversizeHandling": "MATCH"
}
},
"TextTransformations": [{
"Priority": 0,
"Type": "URL_DECODE"
}]
}
},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "SQLInjection"
}
}]'
Managed Rule Groups
# AWS Managed Rules
# - AWSManagedRulesCommonRuleSet: Common attacks
# - AWSManagedRulesSQLiRuleSet: SQL injection
# - AWSManagedRulesKnownBadInputsRuleSet: Known bad inputs
# - AWSManagedRulesAdminProtectRuleSet: Admin path protection
aws wafv2 update-web-acl \
--name my-web-acl \
--scope REGIONAL \
--lock-token lock-token \
--rules '[{
"Name": "AWSManagedRulesCommon",
"Priority": 0,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet"
}
},
"OverrideAction": {"None": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWSManagedRulesCommon"
}
}]'
AWS Shield
AWS Shield
Shield Standard vs Advanced
| Feature | Standard | Advanced |
|---|---|---|
| DDoS Protection | Basic | Advanced |
| Cost | Free | $3,000/month |
| 24/7 DDoS Response Team | No | Yes |
| Cost Protection | No | Yes |
| Advanced Metrics | No | Yes |
| WAF Integration | Yes | Yes |
Shield Advanced
# Enable Shield Advanced
aws shield create-subscription
# Add protection
aws shield create-protection \
--name my-alb-protection \
--resource-arn arn:aws:elasticloadbalancing:us-east-1:xxx:loadbalancer/app/my-alb/xxx
# Create protection group
aws shield create-protection-group \
--protection-group-id my-group \
--aggregation TYPE \
--pattern ALL \
--members '[{
"Type": "APPLICATION_LOAD_BALANCER",
"ResourceId": "xxx"
}]'
# Get subscription details
aws shield describe-subscription
# Get attack details
aws shield describe-dirt-access-event --max-items 10
Shield DDoS Protection
┌─────────────────────────────────────────────────────────────┐
│ Shield Protection Architecture │
├─────────────────────────────────────────────────────────────┤
│ │
│ DDoS Attack ──▶ Shield ──▶ Auto-mitigation │
│ ├── Rate limiting │
│ ├── IP blocking │
│ └── Geographic restriction │
│ │
│ If protection fails: │
│ • AWS credits for scaling costs │
│ • 24/7 DDoS Response Team │
│ • Advanced monitoring │
└─────────────────────────────────────────────────────────────┘
WAF Monitoring and Automation
WAF Monitoring and Automation
CloudWatch Metrics
# Get WAF metrics
aws cloudwatch get-metric-statistics \
--namespace AWS/WAF \
--metric-name AllowedRequests \
--dimensions Name=WebACL,Value=my-web-acl Name=Region,Value=us-east-1 \
--start-time $(date -u -d '1 hour ago') \
--end-time $(date -u) \
--period 300 \
--statistics Sum
# Key metrics:
# - AllowedRequests: Requests allowed by WAF
# - BlockedRequests: Requests blocked by WAF
# - CountedRequests: Requests matched by counting rules
CloudWatch Alarms
# Alarm on high block rate
aws cloudwatch put-metric-alarm \
--alarm-name WAF-High-Block-Rate \
--metric-name BlockedRequests \
--namespace AWS/WAF \
--dimensions Name=WebACL,Value=my-web-acl Name=Region,Value=us-east-1 \
--statistic Sum \
--period 300 \
--threshold 1000 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:xxx:security-alerts
WAF Logging
# Enable logging to S3
aws wafv2 put-logging-configuration \
--logging-configuration '{
"ResourceArn": "arn:aws:wafv2:us-east-1:xxx:regional/webacl/my-web-acl/xxx",
"LogDestinationConfigs": ["arn:aws:s3:::my-waf-logs"],
"RedactedFields": [
{
"SingleHeader": {"Name": "authorization"}
},
{
"SingleHeader": {"Name": "cookie"}
}
]
}'
Automated Responses
# Lambda function for automated IP blocking
import boto3
def lambda_handler(event, context):
# Parse CloudWatch alarm
detail = event['detail']
if detail['state']['value'] == 'ALARM':
# Add IP to block list
waf = boto3.client('wafv2')
waf.update_ip_set(
Name='auto-blocked-ips',
Scope='REGIONAL',
Id='xxx',
Addresses=['attacker-ip/32']
)
WAF Best Practices
WAF Best Practices
Defense in Depth
┌─────────────────────────────────────────────────────────────┐
│ Security Layers │
├─────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: Shield (DDoS protection) │
│ Layer 2: WAF (Application firewall) │
│ Layer 3: Security Groups (Network firewall) │
│ Layer 4: IAM (Access control) │
│ Layer 5: Encryption (Data protection) │
│ │
└─────────────────────────────────────────────────────────────┘
Best Practices
- Start with AWS Managed Rules for common protection
- Use rate-based rules to prevent abuse
- Implement geo-blocking if not serving global users
- Log all requests for forensics
- Use counting mode before blocking to test rules
- Implement automated responses to common attacks
- Monitor metrics and adjust thresholds
- Use rule groups for reusable protection
Cost Optimization
| Feature | Cost |
|---|---|
| WAF Web ACL | $5/month |
| WAF Rules | $1/rule/month |
| WAF Requests | $0.60 per million |
| Managed Rules | $1-10/rule/month |
| Shield Standard | Free |
| Shield Advanced | $3,000/month |
# Use counting mode to test rules before blocking
aws wafv2 update-web-acl \
--name my-web-acl \
--scope REGIONAL \
--lock-token lock-token \
--rules '[{
"Name": "TestRule",
"Priority": 1,
"Statement": {
"SqliMatchStatement": {
"FieldToMatch": {"UriPath": {}},
"TextTransformations": [{"Priority": 0, "Type": "URL_DECODE"}]
}
},
"Action": {"Count": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "TestRule"
}
}]'