AWS WAF and Shield: DDoS Protection and Web Security

Running web applications on AWS without a proper perimeter defense is like leaving your front door wide open. AWS WAF (Web Application Firewall) and AWS Shield together provide a layered security model that stops SQL injection, cross-site scripting, volumetric DDoS floods, and sophisticated bot attacks before they ever reach your application code. This guide walks through every major feature — Web ACLs, managed rule groups, rate-based rules, Shield Advanced, Firewall Manager, and Bot Control — with real CloudFormation templates and Python automation examples you can use immediately.

AWS WAF Overview: Web ACLs, Rules, and WCU

AWS WAF inspects HTTP/HTTPS requests at layer 7 and allows you to block, allow, or count requests based on conditions you define. The top-level construct is a Web ACL (Access Control List), which is a container for an ordered list of rules and rule groups.

Every Web ACL has a default action — either ALLOW or BLOCK — that applies to any request that doesn't match any rule. Rules are evaluated in priority order (lower number = evaluated first). When a rule matches, WAF applies that rule's action (ALLOW, BLOCK, COUNT, or CAPTCHA) and stops evaluating further rules, unless the rule's action is COUNT.

Web ACL Capacity Units (WCU)

WAF enforces a capacity limit on each Web ACL measured in Web ACL Capacity Units (WCU). The default limit is 1,500 WCU per Web ACL (soft limit, can be increased). Each rule and rule group consumes WCU based on complexity:

  • Simple string match rule: 1 WCU
  • Regex match rule: 3–25 WCU depending on complexity
  • SQL injection rule: 20 WCU
  • AWS Managed Rule Group (Core): 700 WCU
  • Bot Control (Common): 50 WCU, (Targeted): 100 WCU

Tracking WCU matters when you stack multiple managed rule groups plus custom rules. If you hit the 1,500 WCU ceiling you'll need to request a quota increase via Service Quotas.

Scope: Regional vs CloudFront

When creating a Web ACL, you choose either Regional (for ALB, API Gateway, AppSync, Cognito) or CloudFront (global scope, must be created in us-east-1). A CloudFront Web ACL is evaluated at the edge PoP closest to the user, which means your ALB never sees blocked traffic — a significant performance and cost advantage.

Rule Types: Managed, Rate-Based, and Custom

AWS Managed Rule Groups

AWS Managed Rules are curated, pre-built rule groups maintained by the AWS Threat Research Team. They're updated automatically when new attack patterns emerge without requiring any changes on your end.

The most commonly used managed rule groups:

  • AWSManagedRulesCommonRuleSet — OWASP Top 10 protection: SQL injection, XSS, path traversal, log4j, Spring4Shell. 700 WCU. Start here.
  • AWSManagedRulesKnownBadInputsRuleSet — Blocks requests matching known bad patterns: PROPFIND, null bytes, path traversal, log injection. 200 WCU.
  • AWSManagedRulesSQLiRuleSet — Dedicated SQL injection detection, more aggressive than the common rule set. 200 WCU.
  • AWSManagedRulesLinuxRuleSet — Linux-specific attack patterns like /etc/passwd traversal. 200 WCU.
  • AWSManagedRulesAmazonIpReputationList — Blocks IPs associated with botnets, scanners, and malicious crawlers. 25 WCU.
  • AWSManagedRulesAnonymousIpList — Blocks Tor exit nodes, VPN endpoints, and hosting providers that frequently originate attacks. 50 WCU.
Tip: When first adding a managed rule group, override all its rules to COUNT mode and monitor CloudWatch metrics for 1–2 weeks before switching to BLOCK. This prevents false positives from breaking legitimate traffic.

Rate-Based Rules

Rate-based rules block IPs that exceed a request threshold within a 5-minute rolling window. The minimum threshold is 100 requests per 5 minutes. You can apply rate-based rules against the full request or aggregate by IP, forwarded IP, custom header value, HTTP method, or query string.

Common patterns:

  • Global rate limit: 2,000 req/5min per IP — catches basic DDoS floods
  • Login endpoint rate limit: 100 req/5min to /api/login — prevents credential stuffing
  • Search endpoint rate limit: 500 req/5min to /search — prevents scraping

Custom Rules

Custom rules let you write precise match conditions using IP sets, regex pattern sets, geo-match, string match, header inspection, and size constraints. These are covered in detail in the Custom Rules section below.

WAF with CloudFront, ALB, API Gateway, AppSync, Cognito

AWS WAF integrates with five AWS resources. You associate a Web ACL directly to the resource — no agent or SDK needed.

CloudFront

Associate a CloudFront-scoped Web ACL to your distribution. WAF evaluation happens at the edge, before the request is forwarded to the origin. Blocked requests never hit your ALB or EC2 — saving compute costs and preventing application-level DDoS impact. CloudFront passes the x-amzn-waf-action header to the origin so you can log the WAF decision.

Application Load Balancer (ALB)

For ALB, create a Regional Web ACL in the same region as the ALB. The association is a one-to-one relationship per ALB. If you have multiple ALBs across accounts, use Firewall Manager (covered later) to manage them centrally.

API Gateway REST API

Associate a Regional WAF Web ACL to a specific API Gateway stage (e.g., /prod). WAF evaluates every request to that stage. This is particularly useful for rate-limiting API consumers and blocking malformed JSON payloads before they hit Lambda.

AppSync GraphQL API

AppSync associations use the same Regional Web ACL as ALB. You can inspect the GraphQL query body using regex or string match rules to block deeply nested queries (GraphQL introspection abuse) or known malicious operation names.

Cognito User Pool

Associating WAF with a Cognito User Pool protects authentication flows — sign-up, sign-in, forgot-password — from credential stuffing and brute force. This is one of the most impactful uses of WAF rate-based rules since Cognito endpoints are publicly accessible.

Building Custom Rules: IP Sets, Geo-Match, Regex, Size Constraints

IP Sets

An IP set is a reusable list of IPv4 or IPv6 CIDR ranges. You reference the IP set from one or more rules. Maximum 10,000 addresses per IP set. IP sets can be updated independently of the Web ACL — useful for dynamic blocklists and allowlists updated by automation (see boto3 example below).

Geo-Match

Geo-match rules evaluate the two-letter country code of the request IP. Use cases: block all traffic except from specific countries (allowlist), block countries with high bot activity, route different rule chains based on geography.

Note: Geo-match accuracy depends on AWS's IP geolocation database. VPN and Tor users can bypass geo restrictions, which is why pairing geo-match with AWSManagedRulesAnonymousIpList is effective.

Regex Pattern Sets

Regex pattern sets let you match against any part of the request: URI, query string, body (first 8 KB), single header, all headers, cookies, or the full request path. Maximum 10 patterns per set, each up to 200 characters. Patterns use the PCRE syntax subset supported by WAF (no lookaheads).

String Match

String match statements evaluate a specific component (URI, header, query string, body) against a literal string. Match types: EXACTLY, STARTS_WITH, ENDS_WITH, CONTAINS, CONTAINS_WORD. String matches cost 1–2 WCU versus 3–25 WCU for regex, so prefer string match when the condition allows it.

Size Constraint

Size constraint rules block requests where a specific component exceeds or is below a byte threshold. Common patterns:

  • Block request bodies over 8 KB (prevents large payload injection)
  • Block URIs over 2,048 bytes (prevents path traversal with long strings)
  • Block query strings over 512 bytes

Code Example 1: WAF Web ACL CloudFormation Template

AWSTemplateFormatVersion: '2010-09-09'
Description: WAF Web ACL for ALB with managed rules + rate limiting

Resources:

  # IP set for manual blocklist
  BlockedIPSet:
    Type: AWS::WAFv2::IPSet
    Properties:
      Name: techoral-blocked-ips
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses: []  # populated via automation

  # Regex pattern set - block suspicious user agents
  SuspiciousUASet:
    Type: AWS::WAFv2::RegexPatternSet
    Properties:
      Name: techoral-suspicious-ua
      Scope: REGIONAL
      RegularExpressionList:
        - "(sqlmap|nikto|masscan|nmap|zgrab|nuclei|dirbuster)"

  TechoralWebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: techoral-web-acl
      Scope: REGIONAL
      DefaultAction:
        Allow: {}
      VisibilityConfig:
        SampledRequestsEnabled: true
        CloudWatchMetricsEnabled: true
        MetricName: TechoralWebACL
      Rules:

        # Rule 1: Block manually blocked IPs (priority 0)
        - Name: BlockListedIPs
          Priority: 0
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: BlockListedIPs
          Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt BlockedIPSet.Arn

        # Rule 2: AWS IP Reputation List (priority 1)
        - Name: AWSIPReputationList
          Priority: 1
          OverrideAction:
            None: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: AWSIPReputationList
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAmazonIpReputationList

        # Rule 3: Core Rule Set (priority 2)
        - Name: AWSCoreRuleSet
          Priority: 2
          OverrideAction:
            None: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: AWSCoreRuleSet
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
              ExcludedRules:
                # Exclude if your app sends large bodies
                - Name: SizeRestrictions_BODY

        # Rule 4: Known Bad Inputs (priority 3)
        - Name: AWSKnownBadInputs
          Priority: 3
          OverrideAction:
            None: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: AWSKnownBadInputs
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet

        # Rule 5: Rate limit per IP — 1000 req/5min (priority 4)
        - Name: RateLimitPerIP
          Priority: 4
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: RateLimitPerIP
          Statement:
            RateBasedStatement:
              Limit: 1000
              AggregateKeyType: IP

        # Rule 6: Tighter rate limit on login endpoint (priority 5)
        - Name: LoginRateLimit
          Priority: 5
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: LoginRateLimit
          Statement:
            RateBasedStatement:
              Limit: 100
              AggregateKeyType: IP
              ScopeDownStatement:
                ByteMatchStatement:
                  SearchString: "/api/auth/login"
                  FieldToMatch:
                    UriPath: {}
                  TextTransformations:
                    - Priority: 0
                      Type: LOWERCASE
                  PositionalConstraint: STARTS_WITH

        # Rule 7: Geo-block high-risk regions (priority 6)
        - Name: GeoBlock
          Priority: 6
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: GeoBlock
          Statement:
            GeoMatchStatement:
              CountryCodes: ["KP", "IR", "CU"]

        # Rule 8: Block suspicious user agents (priority 7)
        - Name: BlockSuspiciousUA
          Priority: 7
          Action:
            Block: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: BlockSuspiciousUA
          Statement:
            RegexPatternSetReferenceStatement:
              Arn: !GetAtt SuspiciousUASet.Arn
              FieldToMatch:
                SingleHeader:
                  Name: "user-agent"
              TextTransformations:
                - Priority: 0
                  Type: LOWERCASE

  # Associate Web ACL to ALB
  WebACLAssociation:
    Type: AWS::WAFv2::WebACLAssociation
    Properties:
      ResourceArn: !Sub "arn:aws:elasticloadbalancing:${AWS::Region}:${AWS::AccountId}:loadbalancer/app/techoral-alb/XXXXXXXX"
      WebACLArn: !GetAtt TechoralWebACL.Arn

Code Example 2: CLI — Create IP Set and Rate-Based Rule

# Create an IP set for known bad actors
aws wafv2 create-ip-set \
  --name "techoral-blocked-ips" \
  --scope REGIONAL \
  --ip-address-version IPV4 \
  --addresses "192.0.2.0/24" "198.51.100.44/32" \
  --region us-east-1

# Output includes the IPSet ARN and LockToken — save these
# {
#   "Summary": {
#     "ARN": "arn:aws:wafv2:us-east-1:123456789012:regional/ipset/techoral-blocked-ips/abc123",
#     "Id": "abc123",
#     "LockToken": "token-xyz"
#   }
# }

# List all Web ACLs in region
aws wafv2 list-web-acls \
  --scope REGIONAL \
  --region us-east-1

# Get current Web ACL configuration
aws wafv2 get-web-acl \
  --name "techoral-web-acl" \
  --scope REGIONAL \
  --id "your-web-acl-id" \
  --region us-east-1

# Create a standalone rate-based rule (via update-web-acl if adding to existing ACL)
# First get the lock token from get-web-acl, then call update-web-acl

# Check WAF sampled requests (last 3 hours, up to 500 samples)
aws wafv2 get-sampled-requests \
  --web-acl-arn "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/techoral-web-acl/id" \
  --rule-metric-name "RateLimitPerIP" \
  --scope REGIONAL \
  --time-window "StartTime=2026-06-06T00:00:00Z,EndTime=2026-06-06T03:00:00Z" \
  --max-items 50 \
  --region us-east-1

# Get WAF metrics from CloudWatch
aws cloudwatch get-metric-statistics \
  --namespace "AWS/WAFV2" \
  --metric-name "BlockedRequests" \
  --dimensions Name=WebACL,Value=techoral-web-acl Name=Region,Value=us-east-1 Name=Rule,Value=RateLimitPerIP \
  --start-time 2026-06-06T00:00:00Z \
  --end-time 2026-06-06T12:00:00Z \
  --period 3600 \
  --statistics Sum \
  --region us-east-1

Code Example 3: Python boto3 — Dynamic IP Blocklist Update

This script reads a list of malicious IPs from an S3 file (e.g., threat feed output) and updates a WAF IP set. It handles the LockToken requirement — WAF uses optimistic locking to prevent concurrent updates from overwriting each other.

import boto3
import json
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

wafv2 = boto3.client('wafv2', region_name='us-east-1')
s3 = boto3.client('s3')

IPSET_NAME = 'techoral-blocked-ips'
IPSET_ID   = 'abc123-your-ipset-id'
SCOPE      = 'REGIONAL'
S3_BUCKET  = 'techoral-security-feeds'
S3_KEY     = 'blocklist/latest.json'
MAX_IPS    = 10000  # WAF IP set hard limit

def load_blocklist_from_s3():
    """Load IP CIDR list from S3 threat feed."""
    response = s3.get_object(Bucket=S3_BUCKET, Key=S3_KEY)
    data = json.loads(response['Body'].read())
    # Expect: {"blocked_ips": ["1.2.3.4/32", "5.6.7.0/24", ...]}
    ips = data.get('blocked_ips', [])
    logger.info(f"Loaded {len(ips)} IPs from S3")
    return ips[:MAX_IPS]  # Trim to WAF limit

def get_ipset_lock_token():
    """Fetch current IP set and its LockToken."""
    response = wafv2.get_ip_set(
        Name=IPSET_NAME,
        Scope=SCOPE,
        Id=IPSET_ID
    )
    return response['IPSet'], response['LockToken']

def update_ipset(addresses: list[str]):
    """Update WAF IP set with new address list."""
    _, lock_token = get_ipset_lock_token()

    if not addresses:
        logger.warning("Empty address list — skipping update to avoid clearing IP set")
        return

    response = wafv2.update_ip_set(
        Name=IPSET_NAME,
        Scope=SCOPE,
        Id=IPSET_ID,
        LockToken=lock_token,
        Addresses=addresses
    )
    logger.info(f"IP set updated. New LockToken: {response['NextLockToken']}")
    return response

def add_ips_to_blocklist(new_ips: list[str]):
    """Merge new IPs into the existing blocklist."""
    current_ipset, lock_token = get_ipset_lock_token()
    existing = set(current_ipset['Addresses'])
    merged = list(existing | set(new_ips))

    if len(merged) > MAX_IPS:
        logger.warning(f"Blocklist would exceed {MAX_IPS} IPs. Trimming oldest.")
        merged = merged[:MAX_IPS]

    response = wafv2.update_ip_set(
        Name=IPSET_NAME,
        Scope=SCOPE,
        Id=IPSET_ID,
        LockToken=lock_token,
        Addresses=merged
    )
    logger.info(f"Added {len(new_ips)} IPs. Total: {len(merged)}")
    return response

def sync_from_threat_feed():
    """Full sync: replace IP set content with latest S3 threat feed."""
    addresses = load_blocklist_from_s3()
    update_ipset(addresses)
    logger.info("Blocklist sync complete")

if __name__ == '__main__':
    # Example 1: Full sync from threat feed
    sync_from_threat_feed()

    # Example 2: Add specific IPs detected by your SIEM
    siem_detections = ["203.0.113.42/32", "203.0.113.99/32"]
    add_ips_to_blocklist(siem_detections)

WAF Logging: Firehose, S3, and CloudWatch

WAF logging writes a JSON record for every evaluated request (ALLOW, BLOCK, COUNT). The log destination must have a name starting with aws-waf-logs-.

Logging Destinations

  • Kinesis Data Firehose — Lowest latency. Firehose can forward to S3 (most common), Splunk, Elasticsearch, or Redshift. Stream name must start with aws-waf-logs-.
  • Amazon S3 — Direct S3 logging (no Firehose needed). Files arrive in AWSLogs/<account>/WAFLogs/<region>/<web-acl-name>/<year>/<month>/<day>/. Files are gzipped JSON.
  • Amazon CloudWatch Logs — Best for near-real-time dashboards and alerting. Log group name must start with aws-waf-logs-. Higher cost at scale but easiest for quick analysis with Insights.

Log Filtering

Log filtering lets you reduce log volume (and cost) by only logging specific requests. You can configure filters on action (ALLOW / BLOCK / COUNT / CAPTCHA), label match (rule that matched), and combination of conditions. For example, only log blocked requests and requests matching the rate-based rule:

# Enable WAF logging to CloudWatch Logs with filtering
aws wafv2 put-logging-configuration \
  --logging-configuration '{
    "ResourceArn": "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/techoral-web-acl/id",
    "LogDestinationConfigs": [
      "arn:aws:logs:us-east-1:123456789012:log-group:aws-waf-logs-techoral"
    ],
    "LoggingFilter": {
      "DefaultBehavior": "DROP",
      "Filters": [
        {
          "Behavior": "KEEP",
          "Conditions": [
            {
              "ActionCondition": {
                "Action": "BLOCK"
              }
            }
          ],
          "Requirement": "MEETS_ANY"
        },
        {
          "Behavior": "KEEP",
          "Conditions": [
            {
              "LabelNameCondition": {
                "LabelName": "awswaf:managed:aws:amazon-ip-list:AWSManagedIPReputationList"
              }
            }
          ],
          "Requirement": "MEETS_ANY"
        }
      ]
    },
    "RedactedFields": [
      {
        "SingleHeader": { "Name": "authorization" }
      },
      {
        "SingleHeader": { "Name": "cookie" }
      }
    ]
  }' \
  --region us-east-1

The RedactedFields configuration replaces sensitive header values with REDACTED in logs — important for PCI-DSS and GDPR compliance.

AWS Shield Standard vs Shield Advanced

Shield Standard

Shield Standard is included at no extra charge with every AWS account. It provides automatic protection against common and most frequently occurring infrastructure-level (Layer 3 and 4) DDoS attacks: UDP floods, SYN floods, DNS reflection, and NTP amplification. Shield Standard protects CloudFront, Route 53, Global Accelerator, EC2, and Elastic Load Balancers automatically.

Standard gives you:

  • Always-on traffic monitoring and detection
  • Automatic inline attack mitigations (no rules to configure)
  • Network flow logging in CloudWatch during active mitigation

Shield Advanced

Shield Advanced costs $3,000/month per organization (flat fee, covers all resources under one account family) plus data transfer OUT fees. It adds:

  • Enhanced L3/L4 protection — larger volumetric attacks, more sophisticated SYN floods, protocol reflection attacks
  • L7 DDoS detection — automatic baseline learning of your application's traffic pattern; creates WAF rules automatically during active attacks
  • AWS Shield Response Team (SRT) access — 24/7 DDoS experts available via AWS Support (Business or Enterprise tier required)
  • Cost protection — AWS credits your account for any EC2, ELB, CloudFront, Route 53 scaling charges caused by a DDoS attack
  • CloudWatch enhanced metrics — DDoSDetected, DDoSAttackBitsPerSecond, DDoSAttackPacketsPerSecond, AttackVector
  • Proactive engagement — SRT contacts you proactively if they detect an active attack on your resources
  • Attack forensics reports — Post-event reports in the Shield console showing attack vector, peak size, and duration
When to use Shield Advanced: If your application is a revenue-critical service (e-commerce checkout, financial platform, gaming backend) or if a 10-minute outage would cost more than $3,000 — the monthly fee pays for itself with a single prevented attack.

DDoS Attack Types and AWS Mitigations

Volumetric Attacks (Layer 3/4)

Volumetric attacks flood your network pipe with traffic — UDP amplification, DNS reflection, ICMP floods. Attack sizes range from a few Gbps to 2+ Tbps. AWS mitigates these at the network edge before traffic reaches your region. Shield Standard handles attacks up to hundreds of Gbps; Shield Advanced handles multi-terabit attacks via AWS's network scrubbing centers.

State Exhaustion Attacks (Layer 4)

SYN floods and TCP connection exhaustion attacks exploit the stateful nature of TCP to overwhelm connection tables on load balancers and servers. AWS ALB and NLB track connection state in the AWS network fabric, which is far more resilient than software-based firewalls. Shield monitors connection rate metrics and activates SYN proxy protections automatically.

Application Layer Attacks (Layer 7)

HTTP floods, Slowloris, RUDY (R-U-Dead-Yet), and GET/POST floods target application-layer resources. A botnet sending legitimate-looking HTTP requests at high volume won't be stopped by Layer 3/4 mitigations. This is where WAF rate-based rules, Bot Control, and Shield Advanced's L7 detection (which auto-creates temporary WAF rules) come in.

When Shield Advanced detects an L7 DDoS, it analyzes the attack traffic, identifies distinguishing characteristics (user agent, request path, header pattern), and automatically creates a WAF BLOCK rule scoped to the attack traffic. This rule is temporary and removed once the attack subsides. The SRT monitors the process in real time.

AWS Firewall Manager: Centralized WAF Policy Management

Firewall Manager lets you define WAF policies once and apply them automatically across all accounts in an AWS Organization. It requires:

  • AWS Organizations with all features enabled
  • A designated Firewall Manager administrator account
  • AWS Config enabled in all accounts and regions

How Policies Work

A Firewall Manager WAF policy specifies:

  • A base set of rules to be prepended or appended to every account's Web ACL
  • Resource scope: which resource types (ALB, API Gateway, CloudFront) and which accounts/OUs to apply to
  • Enforcement mode: Firewall Manager can auto-remediate (create missing Web ACLs) or just report non-compliance

When Firewall Manager creates Web ACLs in member accounts, those accounts can add their own rules in the middle — between the Firewall Manager prepended rules and appended rules. This enables central governance while allowing team-level customization.

Common Enterprise Patterns

  • Prepend: AWSManagedRulesAmazonIpReputationList + Anonymous IP List (enforced everywhere)
  • Each team: adds their application-specific rules and rate limits in the middle
  • Append: Geo-block certain countries organization-wide

Bot Control and Fraud Control Managed Rule Groups

Bot Control

AWS WAF Bot Control is a managed rule group that detects and manages bot traffic. It offers two levels:

  • Common bot protection (50 WCU, $10/month) — Categorizes traffic using signature-based detection. Labels bots as verified (search engines, monitors), category (scraper, scanner, content fetcher), and browser automation. You write rules to act on these labels.
  • Targeted bot protection (100 WCU, $10/month extra) — Adds browser fingerprinting via a JavaScript challenge (like CAPTCHA without a puzzle) and CAPTCHA puzzles for higher-confidence bot detection. Effective against headless browsers like Puppeteer and Playwright that bypass signature detection.

Bot Control adds labels to requests like awswaf:managed:aws:bot-control:bot:category:scraper. You then write custom rules that match on these labels and apply BLOCK, CAPTCHA, or COUNT actions depending on your use case. For example, you might COUNT scraper bots on marketing pages but BLOCK them on checkout pages.

Account Takeover Prevention (ATP)

ATP is a fraud control managed rule group focused on credential stuffing against login endpoints. It:

  • Inspects login form submissions and checks credentials against a compromised credential database (AWS maintains this)
  • Tracks failed login attempts per IP and per username across requests
  • Labels requests with awswaf:managed:aws:atp:aggregate:volumetric:ip:high when threshold exceeded
  • Integrates with Cognito and custom login endpoints via request body inspection

Account Creation Fraud Prevention (ACFP)

ACFP detects bulk account creation (fake account farms used for abuse, promotional code exploitation, fraud). It analyzes registration form submissions, detects common fake-identity patterns, and labels high-risk registration attempts so you can challenge or block them.

Cost Breakdown

ResourceCost
Web ACL$5.00/month per Web ACL
Rule or Rule Group$1.00/month per rule
Requests evaluated$0.60 per million requests
AWS Managed Rule Group$1.00/month per rule group (in addition to the per-rule charge)
Bot Control Common$10.00/month + $1.00 per million requests
Bot Control TargetedAdditional $10.00/month on top of Common
ATP (Account Takeover Prevention)$10.00/month + $1.00 per 1,000 login attempts analyzed
ACFP (Account Creation Fraud Prevention)$10.00/month + $2.00 per 1,000 registration attempts analyzed
Shield StandardFree
Shield Advanced$3,000/month per organization + data transfer OUT charges at standard rate
Firewall Manager (WAF policy)$100.00/month per policy per region
Cost example: A typical production setup — 1 Web ACL ($5) + 5 rules ($5) + Core Rule Set + IP Reputation ($2) + 50M requests/month ($30) + Bot Control Common ($10) — totals around $52/month. For a mid-size SaaS handling 500M requests/month the request cost alone reaches $300/month, making WAF pricing scale-linear with traffic.

Frequently Asked Questions

What is the difference between WAF on CloudFront vs WAF on ALB?

CloudFront WAF evaluates at the edge — blocked requests never reach your VPC, so you save on data transfer and ALB compute. ALB WAF runs in your region after the request traverses CloudFront. If you use CloudFront as your CDN, always put WAF there. If you expose ALB directly (no CloudFront), put WAF on the ALB. You can also stack both — WAF at CloudFront blocks most attacks, WAF at ALB provides defense-in-depth.

Can WAF block all DDoS attacks?

No. WAF operates at Layer 7 (HTTP/HTTPS). It cannot stop Layer 3/4 volumetric attacks that saturate the network pipe before HTTP packets are assembled. Shield Standard and Shield Advanced handle those. For comprehensive coverage you need both: WAF for application-layer threats, Shield for network-layer floods.

How do I avoid false positives with the Core Rule Set?

Start with all rules in COUNT mode for 2 weeks. Review sampled requests in the WAF console and CloudWatch metrics. Identify which rules are triggering on legitimate traffic. Exclude those specific rules by name in the ManagedRuleGroupStatement ExcludedRules list. Common false positives come from SizeRestrictions_BODY (if your app accepts large JSON payloads) and CrossSiteScripting_BODY (if your CMS or rich text editor posts HTML).

Does Shield Advanced automatically create WAF rules during an attack?

Yes. Shield Advanced has an automatic application layer DDoS mitigation feature. When enabled on a resource, Shield monitors your application's traffic baseline and automatically creates temporary WAF BLOCK rules during active L7 attacks. These rules target the specific attack characteristics and are removed when the attack ends. You must associate a WAF Web ACL to the protected resource for this to work.

Is Shield Advanced worth $3,000/month for a startup?

For most startups, no. Shield Standard + WAF Core Rule Set + rate-based rules covers the vast majority of attacks. Shield Advanced makes sense when: (a) you're in a DDoS-targeted industry (gaming, finance, crypto, news media), (b) downtime costs exceed $3,000/hour, (c) you need SRT access for compliance or SLA reasons, or (d) you're running a large multi-account org where the cost protection benefit can recoup fees in a single event.

How do I test WAF rules without breaking production?

Use COUNT action instead of BLOCK when first adding rules. COUNT evaluates the rule and increments the metric but does not block the request. Monitor the CloudWatch metric for false positives. When confident, switch to BLOCK. For new managed rule groups, use OverrideAction: Count in the CloudFormation template, then switch to OverrideAction: None (which means "use the group's own actions") after validation.