# AWS WAF — Practical Baseline for Managed Rules, Rate Limits, and Logging

> **Intro:** AWS WAF is most useful when teams stop treating it as a magic “block bad traffic” switch and start treating it as a **tunable request-filtering layer** in front of CloudFront, ALB, API Gateway, Cognito, App Runner, or other AWS HTTP entry points. This page focuses on a practical default posture for common web attacks, rollout order, tuning, and reusable starter configuration.
>
> **What this page includes**
>
> * where AWS WAF fits in a real AWS edge / ingress design;
> * a sane baseline of AWS Managed Rules and custom rules;
> * practical rate-limit patterns for login, search, and noisy APIs;
> * logging, body-inspection, and tuning notes that reduce false positives;
> * short Terraform-first examples you can adapt quickly.

## What AWS WAF is good at — and what it is not

AWS WAF is a **request inspection and traffic-control layer** for HTTP(S) applications.

It is good at:

* filtering obvious malicious request patterns before they hit the app;
* enforcing rate limits on abusive paths or clients;
* adding managed protections for common web attack signatures;
* labeling and logging traffic so you can tune rules and investigate abuse;
* adding CAPTCHA / challenge friction where full blocking would be too risky.

It is **not** a replacement for:

* authentication and authorization;
* object-level and tenant-level access control;
* secure coding, validation, and output encoding;
* bot / abuse controls in business workflows such as signup, checkout, promo use, or account recovery.

## Where to attach AWS WAF in AWS

Common placements:

* **CloudFront + WAF** for internet-facing web apps, static + dynamic sites, and APIs that already use CloudFront.
* **ALB + WAF** for regional ingress where CloudFront is not required.
* **API Gateway + WAF** for public APIs, especially when request throttling alone is not enough.
* **Cognito user pool + WAF** when auth endpoints themselves are under attack.
* **App Runner / AppSync / Amplify / Verified Access** when those are the AWS-native front doors.

### Practical placement guidance

* Prefer **CloudFront + WAF** when the application is public, latency-sensitive, or exposed globally.
* Prefer **regional WAF on ALB or API Gateway** when the service is regional, internal to a geography, or already fronted by those services directly.
* Do **not** assume the same Web ACL should be reused everywhere without tuning. Login-heavy apps, JSON APIs, GraphQL endpoints, and public brochure sites usually need different custom rules.

```mermaid
flowchart LR
    U[Internet client] --> CF[CloudFront]
    CF --> WAF[AWS WAF Web ACL]
    WAF --> ALB[Application Load Balancer]
    ALB --> APP[Web / API services]
    APP --> DB[(Data stores)]
    APP --> OBS[Logs / metrics / traces]

    WAF -. blocks / counts / challenges .-> U
```

## A sane baseline rule strategy

A useful baseline is usually:

1. **explicit allow/deny context rules**;
2. **rate-based custom rules** for sensitive paths;
3. **AWS Managed Rules baseline groups**;
4. **optional bot / fraud / challenge controls**;
5. **logging and tuning loop**.

### 1) Start with small explicit context rules

Good early custom rules:

* block methods you do not need on specific paths;
* block requests to admin paths from the public internet if they should only exist behind VPN or private access;
* allowlist known monitoring or integration traffic where appropriate;
* enforce host-header expectations if multiple virtual hosts exist.

These rules are often higher signal than giant regex collections.

### 2) Put rate-based rules in front of noisy workflows

Typical high-value rate-limit targets:

* `/login`, `/signin`, `/session`, `/oauth/*`, `/password-reset`;
* search, preview, or export endpoints;
* public JSON APIs that are expensive or abuse-prone;
* GraphQL POST endpoints where a single path hides many operations.

### 3) Add AWS Managed Rules in a staged order

A strong default rollout order for many internet-facing applications is:

| Rule group                                                  | Why start with it                                                         | Typical note                                                     |
| ----------------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `AWSManagedRulesCommonRuleSet`                              | broad baseline for common web exploit patterns                            | start in `Count` if the app is legacy or highly varied           |
| `AWSManagedRulesKnownBadInputsRuleSet`                      | catches clearly suspicious payload patterns                               | usually low-regret to enable early                               |
| `AWSManagedRulesAmazonIpReputationList`                     | blocks IPs associated with malicious activity / recon                     | high-value baseline for public apps                              |
| `AWSManagedRulesAnonymousIpList`                            | useful against evasion, scraping, and abuse via proxies/VPN/Tor           | can be too aggressive for consumer apps or privacy-heavy regions |
| `AWSManagedRulesSQLiRuleSet`                                | important for APIs and dynamic apps with parameterized input              | tune carefully around search/filter behavior                     |
| `AWSManagedRulesAdminProtectionRuleSet`                     | reduces exposure of common admin paths                                    | especially useful if third-party admin surfaces exist            |
| `AWSManagedRulesLinuxRuleSet` or OS / stack-specific groups | adds signatures tied to backend platform families                         | enable only if they fit your stack                               |
| `AWSManagedRulesBotControlRuleSet`                          | optional higher-cost control for scraping / scanner / bot-heavy scenarios | start only when abuse economics justify it                       |

## Recommended starter baselines by app type

### Public website with forms and login

* CommonRuleSet
* KnownBadInputs
* AmazonIpReputationList
* login rate limit
* optional AnonymousIpList
* optional Bot Control for scraping and signup abuse

### Public JSON API behind API Gateway or ALB

* CommonRuleSet
* KnownBadInputs
* SQLiRuleSet
* AmazonIpReputationList
* path-scoped rate limits per high-risk route
* optional CAPTCHA / challenge for suspicious anonymous traffic where browser flows exist

### Admin plane / internal portal exposed through the internet

* CommonRuleSet
* KnownBadInputs
* AmazonIpReputationList
* AdminProtectionRuleSet
* tighter IP allowlists or geo restrictions where operationally acceptable
* aggressive rate limiting on login and MFA-related flows

## Count first, then block

The safest rollout model is usually:

1. deploy new managed groups in **Count** mode;
2. inspect logs and sampled requests;
3. identify false positives and exception candidates;
4. switch stable groups to **Block**;
5. keep expensive or risky groups in Count longer.

This is especially important for:

* legacy apps with odd query formats;
* GraphQL and search-heavy APIs;
* admin routes with automation clients;
* apps that legitimately receive traffic through proxies or privacy networks.

## Rate-limit patterns that actually help

### Login / auth endpoints

Use **low thresholds** with short windows, scoped only to the relevant paths and methods.

Good signals:

* `POST /login`
* `POST /oauth/token`
* password reset request endpoints
* MFA verification endpoints

Prefer separate rules for:

* human browser login;
* API token issuance;
* admin login.

### Search, export, report, and preview endpoints

These are common abuse magnets because they are computationally expensive and often scrape-friendly.

Use:

* slightly higher rate limits than login;
* per-IP or forwarded-IP aggregation;
* path-specific scope-down statements;
* block or challenge depending on customer experience tolerance.

### GraphQL and generic POST APIs

Because many actions share one path, add rate limits and then use other signals such as headers, operation names at the app layer, or bot controls if needed.

Do not expect WAF alone to distinguish cheap and expensive business operations inside a single API path.

## Logging, visibility, and investigation

A practical WAF deployment should always include:

* **request logging** to a central destination;
* **sampled requests** for tuning;
* **CloudWatch metrics / alarms** per important rule;
* correlation with application logs and identity events.

Good operating habits:

* alert on sudden increases in blocked requests, CAPTCHA / challenge activity, and rate-limit hits;
* create separate dashboards for login abuse, bot patterns, and generic managed-rule matches;
* keep WAF logs joined with edge / ALB / API Gateway logs when investigating attacks.

## Request body size and inspection caveats

WAF body inspection is not infinite.

Practical review questions:

* are the critical attack inputs located in headers, query strings, URI, cookies, or body?
* does the protected resource type forward enough body bytes for the attack class you care about?
* are file-upload or large-JSON endpoints relying too heavily on WAF body inspection instead of application validation?

If the app accepts large bodies, use WAF as a **front filter**, not as the only detection layer.

## Tuning patterns that reduce pain

### Use path-specific scope-down statements

Do not apply the same threshold or same custom logic to the whole site if only a few routes are risky.

### Use labels and follow-on rules deliberately

Managed rules can label requests. That makes it easier to:

* count first;
* observe the label distribution;
* write smaller follow-on rules for challenge, rate-limit, or block actions.

### Exclude carefully, not broadly

If a rule causes false positives:

* identify the exact sub-rule or route behavior;
* scope the exception as narrowly as possible;
* document why the exception exists;
* revisit the exception after application changes.

### Tune by environment

A production Web ACL should not be tuned only against synthetic traffic. Tune against:

* staging traffic that resembles production;
* production traffic in Count mode;
* attack simulations for login abuse, SQLi payloads, suspicious headers, and bot-like scraping.

## Terraform starter example

See: [AWS WAF v2 baseline Web ACL (Terraform)](https://github.com/D3One/Product-Security-Gitbook/blob/main/snippets/cloud/aws-waf-v2-baseline-web-acl.tf)

This starter demonstrates:

* a WAFv2 Web ACL;
* a scoped login rate-limit rule;
* common AWS Managed Rules groups;
* visibility configuration and a logging hook.

## Example: custom login rate-limit logic

```hcl
statement {
  rate_based_statement {
    limit              = 100
    evaluation_window_sec = 60
    aggregate_key_type = "IP"

    scope_down_statement {
      and_statement {
        statement {
          byte_match_statement {
            field_to_match {
              uri_path {}
            }
            positional_constraint = "EXACTLY"
            search_string         = "/login"
            text_transformation {
              priority = 0
              type     = "NONE"
            }
          }
        }
        statement {
          byte_match_statement {
            field_to_match {
              method {}
            }
            positional_constraint = "EXACTLY"
            search_string         = "POST"
            text_transformation {
              priority = 0
              type     = "NONE"
            }
          }
        }
      }
    }
  }
}
```

This is deliberately simple. In a real deployment, tune the threshold from production traffic and decide whether to **Block**, **Count**, **CAPTCHA**, or **Challenge** based on user experience and threat model.

## Example: protecting an admin path more aggressively

If `/admin` should never be reachable from the open internet, use:

* network restriction or private access first;
* then WAF allow/deny rules as a second barrier;
* then AdminProtection managed rules as a generic cleanup layer.

WAF should not be the only thing protecting an admin plane.

## Operational anti-patterns

* enabling many managed groups in Block mode on day one without Count / tuning;
* using one Web ACL unchanged for brochure sites, APIs, and admin portals;
* relying on Anonymous IP blocking for customer apps where real users legitimately come through VPNs or privacy relays;
* expecting WAF to solve SSRF, broken authorization, or tenant-isolation flaws;
* ignoring logging because “managed rules are enough”;
* treating body inspection limits as if they cover all payload risk.

## Fast rollout checklist

A reasonable AWS WAF baseline is usually ready when:

* the correct protected resource is chosen;
* at least one high-risk path has a scoped rate limit;
* the baseline managed groups are enabled and tested in Count mode;
* logging and dashboards are turned on;
* false-positive handling is documented;
* the team knows which routes are safe to challenge, and which must only count or block.

## Read next

* [AWS Security Baseline and Top Misconfigurations](/cloud-kubernetes-and-infrastructure-security/index/aws-security-baseline-and-top-misconfigurations.md)
* [Cloud Auditing by API and Configuration State](/cloud-kubernetes-and-infrastructure-security/index/cloud-auditing-by-api-and-configuration-state.md)
* [Cloud Audit Cookbook by Provider](/cloud-kubernetes-and-infrastructure-security/index/cloud-audit-cookbook-by-provider.md)
* [API Abuse Resilience and Rate Limits](/architecture-api-crypto-and-identity/index/api-abuse-resilience-and-rate-limits.md)
* [Account Takeover, Automation, and Bot Abuse](/application-security-and-secure-sdlc/index-3/account-takeover-automation-and-bot-abuse.md)

***

*Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/cloud-kubernetes-and-infrastructure-security/index/aws-waf-practical-baseline-managed-rules-rate-limits-and-logging.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
