Carrier-grade NAT means thousands of legitimate mobile users share a handful of public IPs. A blunt IP rate rule that works for desktop web will false-positive entire cell towers during a product launch—while distributed credential stuffing still slips through on residential proxies. Tune for identity signals, not only source IP.
⚡ TL;DR: Prefer composite keys (IP + device/app attestation + route) over raw IP limits for mobile APIs. Use higher IP thresholds with lower per-token/session limits. Label CGNAT ranges; separate login endpoints. Pair with Multi-Tenant Rate Limits, SSRF Hardening in Node, and Continuous Path Verification.
Why IP-only rules fail on mobile
Desktop: 1 user ≈ 1 IP → IP rate ≈ user rate
Mobile CGNAT: 500–5000 users ≈ 1 IP → IP rate false-positives
Botnets: 1 attacker ≈ many IPs → IP rate false-negatives
AWS WAF rate-based rules aggregate on IP by default. For mobile APIs behind API Gateway or CloudFront, that aggregation is often the wrong unit.
Layered limits that survive CGNAT
{
"Name": "login-per-ip-loose",
"Priority": 10,
"Action": { "Block": {} },
"Statement": {
"RateBasedStatement": {
"Limit": 2000,
"AggregateKeyType": "IP",
"ScopeDownStatement": {
"ByteMatchStatement": {
"SearchString": "/v1/auth/login",
"FieldToMatch": { "UriPath": {} },
"PositionalConstraint": "STARTS_WITH",
"TextTransformations": [{ "Priority": 0, "Type": "NONE" }]
}
}
}
}
}
// App-layer token bucket (Redis) keyed by user/device — true fairness
// See multi-tenant rate limits deep-dive for cluster-safe bucketing
const key = `rl:login:${deviceId || "anon"}:${route}`;
await redis.tokenBucket(key, { rate: 5, burst: 10, windowMs: 60_000 });
| Layer | Key | Typical budget |
|---|---|---|
| WAF | IP (login path only) | High (e.g. 1k–2k/5m) |
| Edge | JA3 / app attestation | Medium |
| App | userId / deviceId | Strict (auth abuse) |
| App | password hash + IP | Credential stuffing |
✅ Strict app-layer identity limits + loose IP backstop.
❌ Single global 100 requests / 5 min / IP on all routes.
Labeling and exceptions
Maintain a supervised list of known CGNAT / mobile ASN ranges for dashboards—not for blanket allowlists (attackers abuse those too). Prefer challenge actions (CAPTCHA/managed challenge) over hard blocks on borderline IPs for interactive clients; keep hard blocks for clearly abusive automation signatures.
# CloudWatch metric filters: track WAF BlockedRequests by rule + country
# Page when BlockedRequests spike correlates with mobile conversion drop
# (canary: continuous path verification on /auth and /pay)
Wire synthetic canaries from mobile egress ASNs so you detect self-DoS before App Store reviews spike—see Continuous Path Verification.
Closing checklist
- [ ] Login and write routes have separate WAF rate scopes
- [ ] IP limits are high enough for CGNAT; identity limits are strict
- [ ] App attestation / device keys feed app-layer buckets
- [ ] Challenge preferred over block for borderline interactive traffic
- [ ] Metrics join WAF blocks with conversion / auth success
- [ ] Mobile ASN canaries exercise auth and pay paths
Related reading
- Multi-Tenant Rate Limits: Redis Cluster Token Buckets Without Hot Keys
- Continuous Path Verification: Minute Canaries for Auth, Pay, and Search
- SLA Error Budgets: Drive Automated Load Shedding Before Hard Outages
- SSRF Hardening in Node: Block Metadata and DNS Rebinding on Fetches
Last updated on September 11, 2026
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
