npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- When deploying new web applications or APIs behind cloud load balancers requiring OWASP protection
- When application penetration testing reveals SQL injection, XSS, or other injection vulnerabilities
- When experiencing brute force, credential stuffing, or bot attacks against authentication endpoints
- When compliance requirements mandate a WAF for PCI-DSS or similar standards
- When tuning WAF rules to reduce false positives blocking legitimate application traffic
Do not use for network-level DDoS protection (use AWS Shield or Azure DDoS Protection), for API authentication design (see managing-cloud-identity-with-okta), or for application code-level security fixes (WAF is a compensating control, not a replacement for secure code).
Prerequisites
- AWS ALB/CloudFront, Azure Application Gateway, or Cloudflare configured as the application entry point
- Application traffic logs for baseline analysis before WAF deployment
- Test environment for validating WAF rules before production enforcement
- Understanding of application request patterns to minimize false positives
Workflow
Step 1: Deploy Managed Rule Sets
Enable cloud provider managed rule sets that cover OWASP Top 10 vulnerabilities. Start in Count (detection) mode before switching to Block (prevention) mode.
# AWS WAF: Create Web ACL with AWS Managed Rules
aws wafv2 create-web-acl \
--name production-waf \
--scope REGIONAL \
--default-action '{"Allow": {}}' \
--visibility-config '{
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "production-waf"
}' \
--rules '[
{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet"
}
},
"OverrideAction": {"Count": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "CommonRuleSet"
}
},
{
"Name": "AWSManagedRulesSQLiRuleSet",
"Priority": 2,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesSQLiRuleSet"
}
},
"OverrideAction": {"Count": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "SQLiRuleSet"
}
},
{
"Name": "AWSManagedRulesKnownBadInputsRuleSet",
"Priority": 3,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesKnownBadInputsRuleSet"
}
},
"OverrideAction": {"Count": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "KnownBadInputs"
}
}
]'Step 2: Create Custom Rate Limiting Rules
Deploy rate-based rules to protect login endpoints against brute force and credential stuffing attacks.
# Rate limiting rule for login endpoint (100 requests per 5 minutes per IP)
aws wafv2 update-web-acl \
--name production-waf \
--scope REGIONAL \
--id <web-acl-id> \
--lock-token <lock-token> \
--default-action '{"Allow": {}}' \
--rules '[
{
"Name": "RateLimitLogin",
"Priority": 0,
"Statement": {
"RateBasedStatement": {
"Limit": 100,
"AggregateKeyType": "IP",
"ScopeDownStatement": {
"ByteMatchStatement": {
"FieldToMatch": {"UriPath": {}},
"PositionalConstraint": "STARTS_WITH",
"SearchString": "/api/auth/login",
"TextTransformations": [{"Priority": 0, "Type": "LOWERCASE"}]
}
}
}
},
"Action": {"Block": {"CustomResponse": {"ResponseCode": 429}}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateLimitLogin"
}
}
]'Step 3: Configure Geo-Blocking and IP Reputation
Block traffic from countries where the application has no legitimate users and leverage IP reputation lists to block known malicious sources.
# AWS WAF: Geo-blocking rule
# Block countries not in the allowed list
aws wafv2 create-ip-set \
--name blocked-ips \
--scope REGIONAL \
--ip-address-version IPV4 \
--addresses "198.51.100.0/24" "203.0.113.0/24"
# Add Amazon IP Reputation rule
# AWSManagedRulesAmazonIpReputationList blocks IPs flagged by AWS threat intelligenceStep 4: Tune Rules to Reduce False Positives
Analyze WAF logs in Count mode to identify legitimate requests being flagged. Create rule exceptions for specific URI paths or request patterns.
# Enable WAF logging to S3
aws wafv2 put-logging-configuration \
--logging-configuration '{
"ResourceArn": "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/production-waf/id",
"LogDestinationConfigs": ["arn:aws:s3:::waf-logs-bucket"],
"RedactedFields": [{"SingleHeader": {"Name": "authorization"}}]
}'
# Query WAF logs with Athena to find false positives
# Find rules triggered most frequently for legitimate traffic
cat << 'EOF' > waf-analysis.sql
SELECT
terminatingRuleId,
httpRequest.uri,
httpRequest.httpMethod,
COUNT(*) as block_count
FROM waf_logs
WHERE action = 'BLOCK'
AND timestamp > date_add('day', -7, now())
GROUP BY terminatingRuleId, httpRequest.uri, httpRequest.httpMethod
ORDER BY block_count DESC
LIMIT 20
EOF# Exclude specific rule from managed rule set that causes false positives
# Example: Exclude SizeRestrictions_BODY for file upload endpoint
aws wafv2 update-web-acl \
--name production-waf \
--scope REGIONAL \
--id <web-acl-id> \
--lock-token <lock-token> \
--rules '[{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet",
"ExcludedRules": [{"Name": "SizeRestrictions_BODY"}]
}
},
"OverrideAction": {"None": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "CommonRuleSet"
}
}]'Step 5: Switch to Block Mode After Validation
After 7-14 days of Count mode with acceptable false positive rates, switch managed rules to Block mode for active protection.
# Change OverrideAction from Count to None (use rule group's default Block action)
# Update each managed rule group from {"Count": {}} to {"None": {}}
# Monitor CloudWatch metrics for sudden changes in blocked request volumeKey Concepts
| Term | Definition |
|---|---|
| Web ACL | Web Access Control List defining the set of rules evaluated against every HTTP request to a protected resource |
| Managed Rule Group | Pre-configured rule set maintained by the cloud provider or third-party vendor covering common attack patterns |
| Rate-Based Rule | WAF rule that tracks request rates per IP address and blocks IPs exceeding the threshold within a time window |
| Count Mode | WAF action that logs matching requests without blocking them, used for rule validation before enforcement |
| Rule Priority | Numerical ordering determining which rules are evaluated first; lower numbers have higher priority |
| Custom Response | WAF capability to return specific HTTP status codes and headers when blocking requests |
| Scope-Down Statement | Condition that narrows a rate-based rule to specific URI paths, methods, or headers |
| False Positive | Legitimate request incorrectly blocked by a WAF rule, requiring rule tuning or exclusion |
Tools & Systems
- AWS WAF: Cloud-native WAF integrated with ALB, CloudFront, API Gateway, and AppSync
- Azure WAF: Web application firewall on Application Gateway or Front Door with OWASP CRS rule sets
- AWS Firewall Manager: Centralized WAF policy management across multiple AWS accounts in an Organization
- WAF Security Automations: AWS solution that deploys Lambda-based automated WAF rule updates based on log analysis
- CloudWatch Metrics: Monitoring dashboard for tracking WAF rule match rates, block counts, and allowed requests
Common Scenarios
Scenario: Credential Stuffing Attack Against Authentication API
Context: An e-commerce application experiences 50,000 login attempts per hour from a botnet using stolen credential lists. The attacker rotates source IPs every few minutes to evade simple IP-based blocking.
Approach:
- Deploy rate-based rules limiting login endpoint requests to 10 per 5 minutes per IP
- Enable AWS WAF Bot Control managed rule group to detect automated request patterns beyond IP rotation
- Add a custom rule requiring valid CAPTCHA tokens for login requests exceeding 5 failures
- Implement IP reputation blocking using AWSManagedRulesAmazonIpReputationList
- Create a custom rule matching on User-Agent patterns common to credential stuffing tools
- Monitor blocked request metrics and adjust thresholds based on legitimate traffic patterns
Pitfalls: Setting rate limits too aggressively blocks legitimate users behind shared NAT IPs. Blocking by User-Agent alone is easily bypassed by rotating agent strings.
Output Format
Cloud WAF Configuration Report
================================
Web ACL: production-waf
Scope: Regional (us-east-1)
Protected Resources: ALB (arn:aws:elasticloadbalancing:...)
Report Date: 2025-02-23
RULE CONFIGURATION:
[P0] RateLimitLogin - BLOCK (100 req/5min/IP)
[P1] AWSManagedRulesCommon - BLOCK (1 exclusion: SizeRestrictions_BODY)
[P2] AWSManagedRulesSQLi - BLOCK
[P3] AWSManagedRulesKnownBad - BLOCK
[P4] AWSManagedRulesBotControl - COUNT (evaluation phase)
[P5] GeoBlockRule - BLOCK (12 countries blocked)
TRAFFIC ANALYSIS (Last 7 Days):
Total Requests: 2,847,293
Allowed: 2,791,456 (98.0%)
Blocked: 51,234 (1.8%)
Counted: 4,603 (0.2%)
TOP BLOCKED RULES:
RateLimitLogin: 23,456 blocks (45.8%)
SQLi Detection: 8,234 blocks (16.1%)
CommonRuleSet (XSS): 7,891 blocks (15.4%)
GeoBlockRule: 6,543 blocks (12.8%)
KnownBadInputs: 5,110 blocks (10.0%)
FALSE POSITIVE ANALYSIS:
Reported False Positives: 3
Confirmed False Positives: 1 (SizeRestrictions_BODY for /api/upload)
Action Taken: Rule exclusion appliedReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.3 KB
API Reference: Implementing Cloud WAF Rules
Libraries
boto3 -- AWS WAFv2
- Install:
pip install boto3 - Docs: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/wafv2.html
Key Methods
| Method | Description |
|---|---|
create_web_acl() |
Create a new Web ACL |
update_web_acl() |
Add/modify rules in a Web ACL |
get_web_acl() |
Retrieve Web ACL details and rules |
list_web_acls() |
List all Web ACLs in scope |
associate_web_acl() |
Attach ACL to ALB, API Gateway, CloudFront |
get_sampled_requests() |
View sampled WAF request data |
list_available_managed_rule_groups() |
List AWS managed rule sets |
create_ip_set() |
Create IP allowlist/blocklist |
create_regex_pattern_set() |
Custom regex matching patterns |
AWS Managed Rule Groups
| Name | Protection |
|---|---|
AWSManagedRulesCommonRuleSet |
OWASP core (XSS, LFI, RFI) |
AWSManagedRulesSQLiRuleSet |
SQL injection |
AWSManagedRulesKnownBadInputsRuleSet |
Known exploit patterns |
AWSManagedRulesLinuxRuleSet |
Linux LFI patterns |
AWSManagedRulesBotControlRuleSet |
Bot detection/management |
AWSManagedRulesATPRuleSet |
Account takeover prevention |
AWSManagedRulesAnonymousIpList |
VPN/proxy/Tor blocking |
Rule Statement Types
ManagedRuleGroupStatement-- AWS or marketplace managed rulesRateBasedStatement-- Rate limiting by IP (100-2B req/5min)GeoMatchStatement-- Country-based blockingByteMatchStatement-- Custom string/header matchingSqliMatchStatement-- SQL injection detectionXssMatchStatement-- Cross-site scripting detectionRegexPatternSetReferenceStatement-- Custom regex rulesIPSetReferenceStatement-- IP allowlist/blocklist
Rule Actions
Allow-- Permit the requestBlock-- Reject with 403Count-- Log only (for testing rules)CAPTCHA-- Challenge with CAPTCHAChallenge-- Silent browser challenge
External References
- AWS WAF Developer Guide: https://docs.aws.amazon.com/waf/latest/developerguide/
- Managed Rules List: https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html
- Azure WAF: https://learn.microsoft.com/en-us/azure/web-application-firewall/
- Cloudflare WAF: https://developers.cloudflare.com/waf/
Scripts 1
agent.py8.2 KB
#!/usr/bin/env python3
"""Cloud WAF rules management agent using AWS WAFv2 boto3 client."""
import json
import sys
import argparse
from datetime import datetime
try:
import boto3
from botocore.exceptions import ClientError
except ImportError:
print("Install boto3: pip install boto3")
sys.exit(1)
MANAGED_RULE_GROUPS = [
{"vendor": "AWS", "name": "AWSManagedRulesCommonRuleSet",
"description": "OWASP Top 10 core protection"},
{"vendor": "AWS", "name": "AWSManagedRulesSQLiRuleSet",
"description": "SQL injection protection"},
{"vendor": "AWS", "name": "AWSManagedRulesKnownBadInputsRuleSet",
"description": "Known malicious input patterns"},
{"vendor": "AWS", "name": "AWSManagedRulesLinuxRuleSet",
"description": "Linux-specific LFI protection"},
{"vendor": "AWS", "name": "AWSManagedRulesBotControlRuleSet",
"description": "Bot management and detection"},
{"vendor": "AWS", "name": "AWSManagedRulesATPRuleSet",
"description": "Account takeover prevention"},
]
def get_waf_client(region="us-east-1", scope="REGIONAL"):
"""Create WAFv2 client."""
return boto3.client("wafv2", region_name=region)
def create_web_acl(client, name, scope="REGIONAL", description=""):
"""Create a new Web ACL with default block action."""
try:
resp = client.create_web_acl(
Name=name, Scope=scope,
DefaultAction={"Allow": {}},
Description=description or f"WAF ACL managed by agent - {name}",
VisibilityConfig={
"SampledRequestsEnabled": True, "CloudWatchMetricsEnabled": True,
"MetricName": name.replace("-", "")},
Rules=[])
return {"arn": resp["Summary"]["ARN"], "id": resp["Summary"]["Id"],
"status": "created"}
except ClientError as e:
return {"error": str(e)}
def add_managed_rule_group(client, acl_name, acl_id, lock_token, scope,
vendor, rule_group_name, priority):
"""Add a managed rule group to an existing Web ACL."""
try:
acl = client.get_web_acl(Name=acl_name, Scope=scope, Id=acl_id)
rules = acl["WebACL"]["Rules"]
lock_token = acl["LockToken"]
rules.append({
"Name": rule_group_name,
"Priority": priority,
"Statement": {
"ManagedRuleGroupStatement": {"VendorName": vendor, "Name": rule_group_name}},
"OverrideAction": {"None": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": True, "CloudWatchMetricsEnabled": True,
"MetricName": rule_group_name}})
client.update_web_acl(
Name=acl_name, Scope=scope, Id=acl_id, LockToken=lock_token,
DefaultAction={"Allow": {}}, Rules=rules,
VisibilityConfig=acl["WebACL"]["VisibilityConfig"])
return {"rule_group": rule_group_name, "status": "added", "priority": priority}
except ClientError as e:
return {"rule_group": rule_group_name, "error": str(e)}
def create_rate_limit_rule(client, acl_name, acl_id, scope, limit=2000, priority=1):
"""Create a rate-limiting rule for DDoS/brute-force protection."""
try:
acl = client.get_web_acl(Name=acl_name, Scope=scope, Id=acl_id)
rules = acl["WebACL"]["Rules"]
lock_token = acl["LockToken"]
rules.append({
"Name": "RateLimitRule",
"Priority": priority,
"Statement": {"RateBasedStatement": {"Limit": limit, "AggregateKeyType": "IP"}},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": True, "CloudWatchMetricsEnabled": True,
"MetricName": "RateLimitRule"}})
client.update_web_acl(
Name=acl_name, Scope=scope, Id=acl_id, LockToken=lock_token,
DefaultAction={"Allow": {}}, Rules=rules,
VisibilityConfig=acl["WebACL"]["VisibilityConfig"])
return {"rule": "RateLimitRule", "limit": limit, "status": "created"}
except ClientError as e:
return {"error": str(e)}
def create_geo_block_rule(client, acl_name, acl_id, scope, country_codes, priority=2):
"""Create a geo-blocking rule for specified country codes."""
try:
acl = client.get_web_acl(Name=acl_name, Scope=scope, Id=acl_id)
rules = acl["WebACL"]["Rules"]
lock_token = acl["LockToken"]
rules.append({
"Name": "GeoBlockRule",
"Priority": priority,
"Statement": {"GeoMatchStatement": {"CountryCodes": country_codes}},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": True, "CloudWatchMetricsEnabled": True,
"MetricName": "GeoBlockRule"}})
client.update_web_acl(
Name=acl_name, Scope=scope, Id=acl_id, LockToken=lock_token,
DefaultAction={"Allow": {}}, Rules=rules,
VisibilityConfig=acl["WebACL"]["VisibilityConfig"])
return {"rule": "GeoBlockRule", "countries": country_codes, "status": "created"}
except ClientError as e:
return {"error": str(e)}
def list_web_acls(client, scope="REGIONAL"):
"""List all Web ACLs."""
try:
resp = client.list_web_acls(Scope=scope)
return [{"name": acl["Name"], "id": acl["Id"], "arn": acl["ARN"]}
for acl in resp.get("WebACLs", [])]
except ClientError as e:
return [{"error": str(e)}]
def get_sampled_requests(client, acl_arn, rule_metric, scope="REGIONAL", max_items=100):
"""Get sampled requests for WAF rule analysis."""
try:
resp = client.get_sampled_requests(
WebAclArn=acl_arn, RuleMetricName=rule_metric, Scope=scope,
TimeWindow={"StartTime": datetime.utcnow().replace(hour=0, minute=0),
"EndTime": datetime.utcnow()},
MaxItems=max_items)
return [{"action": r["Action"], "uri": r["Request"]["URI"],
"method": r["Request"]["Method"],
"country": r["Request"].get("Country", ""),
"source_ip": r["Request"]["ClientIP"]}
for r in resp.get("SampledRequests", [])]
except ClientError as e:
return [{"error": str(e)}]
def run_waf_audit(region="us-east-1", scope="REGIONAL"):
"""Run WAF configuration audit."""
client = get_waf_client(region, scope)
print(f"\n{'='*60}")
print(f" AWS WAF CONFIGURATION AUDIT")
print(f" Region: {region} | Scope: {scope}")
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*60}\n")
acls = list_web_acls(client, scope)
print(f"--- WEB ACLs ({len(acls)}) ---")
for acl in acls:
if "error" in acl:
print(f" Error: {acl['error']}")
continue
print(f" {acl['name']} ({acl['id']})")
try:
detail = client.get_web_acl(Name=acl["name"], Scope=scope, Id=acl["id"])
rules = detail["WebACL"]["Rules"]
print(f" Rules: {len(rules)}")
for r in rules:
print(f" [{r['Priority']}] {r['Name']}")
except ClientError:
pass
print(f"\n--- AVAILABLE MANAGED RULE GROUPS ---")
for mrg in MANAGED_RULE_GROUPS:
print(f" {mrg['name']}: {mrg['description']}")
print(f"\n{'='*60}\n")
return {"acls": acls}
def main():
parser = argparse.ArgumentParser(description="Cloud WAF Rules Agent")
parser.add_argument("--region", default="us-east-1")
parser.add_argument("--scope", default="REGIONAL", choices=["REGIONAL", "CLOUDFRONT"])
parser.add_argument("--audit", action="store_true", help="Audit WAF configuration")
parser.add_argument("--create-acl", help="Create new Web ACL with given name")
parser.add_argument("--output", help="Save report to JSON")
args = parser.parse_args()
if args.audit:
report = run_waf_audit(args.region, args.scope)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
elif args.create_acl:
client = get_waf_client(args.region, args.scope)
result = create_web_acl(client, args.create_acl, args.scope)
print(json.dumps(result, indent=2))
else:
parser.print_help()
if __name__ == "__main__":
main()