速率限制失败,通常不是因为上限太松,而是问错了问题。在决定“每分钟多少次”之前,需要先回答三个问题:按谁计数、计什么、达到上限时怎么处理。
问题1:按谁计数?
以 IP 为主轴,对攻击者和正常用户两头都失效
攻击者一侧:在反向代理或 CDN 后面,应用看到的来源地址可能是写在请求头里的值。无条件信任 X-Forwarded-For,改写一个请求头就足以被当成另一个人。你以为在计数,其实什么也没数到。这个请求头能信任到什么程度,见 X-Forwarded-For 伪造与可信代理。
正常用户一侧:企业 NAT 和移动网络意味着许多无关的用户共用一个地址。按 IP 限制,就会限制到并没有攻击你的人。
所以主轴应该是与行为主体绑定的标识——账户、API 密钥、已建立的会话——再把 IP 叠加为辅助信号。在未认证阶段(登录之前)没有可以作为键的主体,这正是后面两个问题要覆盖的部分。
问题2:计什么?
只数请求次数的设计,挡不住单次就很昂贵的请求。OWASP API Security Top 10 在 API4:2023“Unrestricted Resource Consumption(不受限制的资源消耗)”中明确列出了需要上限的项目。
你在数的东西
请求次数:100次/分钟 → 未超上限 ✓
↓ 但实际消耗的是
CPU · 时间
每次全表扫描
内存
超大的输入
带宽
一万条记录
金钱
反复的计费调用
= 从未触及上限就被耗尽
- 时间和内存
- 执行超时、最大内存分配
- 操作系统资源
- 文件描述符数量、进程数量
- 输入大小
- 上传文件的最大大小、输入参数的最大大小
- 每次请求的工作量
- 单个 API 客户端请求中执行的操作数、每页返回的记录数
- 金钱
- 第三方服务和 API 集成的费用上限(见下文;防止经济损失的最后一道控制)
如果一次请求返回一万条记录、处理一个巨大的文件、或者多次调用按量计费的外部 API,那么守住“每分钟100次”什么也保护不了。让计数单位与你要保护的东西一致——CPU、内存、带宽、金钱。这是设计的核心。
问题3:达到上限时怎么处理?
这是最容易误解的部分。更严格并不自动等于更安全。
粗暴锁定的副作用
“失败3次就冻结账户”听起来没错,但这也意味着攻击者可以故意冻结别人的账户——你把锁定变成了一个针对自己用户的拒绝服务工具。挡住了暴力破解,却交付了一个把人关在门外的手段。
按“不划算”来设计
让尝试变慢,而不是阻断访问。NIST SP 800-63B 列出的有:认证前要求 CAPTCHA、失败后的等待时间随着账户接近上限而延长、用户以前认证成功过的 IP 地址白名单,以及判断行为是否在正常范围内的基于风险或自适应的技术(地址、地理位置、时间、浏览器元数据)。
NIST 的数字比你想的大:连续失败100次
NIST SP 800-63B 写明“验证方必须(SHALL)把单个账户的连续认证失败次数限制在100次以内”。常见的“3次就锁定”并不是标准的要求。
为什么100次就够:一旦路径上有了延迟和 CAPTCHA,要在有意义的时间内达到100次就不现实了。反过来说——只收紧次数而不加延迟是最糟的组合:既把正常用户关在门外,又让自动化攻击能很快用完尝试次数。
同一份文档还有一个实用的提示:认证成功时,验证方应当(SHOULD)忽略该用户此前来自同一 IP 地址的失败次数。计数器何时归零也要决定——这同样是设计的一部分。
在哪里用什么
登录(暴力破解和撞库)
以账户为单位的失败计数器为主轴,让延迟逐步延长。IP 作为辅助信号,绝不作为唯一依据。加上多因素认证后,即使密码正确也不能立即登录,猜密码就变得不划算。另外请注意,近来的入侵越来越多是带着有效凭据进来,而不是靠猜(2026年入侵途径分析)——速率限制是必要的,但不充分。
密码重置和确认邮件(邮件轰炸)
既要统计能触发发送的来源,也要统计发往同一目标的数量。接受别人地址的表单,会让攻击者同时骚扰第三方并损害你的发信信誉。把按目标的冷却时间、重发的最小间隔、以及删除长期未确认的记录结合起来(这也能减少你持有的未经验证的个人数据)。重置路径本身见密码重置的设计缺陷。
公开端点和 AI 功能(费用暴涨)
计成本,而不是计请求。限制输入大小,限制每次请求执行的操作数,并一定要设置服务商一侧的费用上限。OWASP 的场景中有账单从每月13美元涨到8,000美元的例子。把按量计费的外部 API 接到公开功能上时,要确保有一层在你自己的代码出错时仍然有效。密钥泄露后会发生什么,见密钥被盗、账单和账户被封和从 AI 写的代码中泄露的 API 密钥。
昂贵的操作(搜索、导出、文件处理)
给执行时间、内存、上传大小和每页返回的记录数设置明确的上限。没有上限的地方,一次请求就能耗尽你的资源。在容器或无服务器层也限制内存、CPU 和进程数,这样使用了意外资源的应用会从外部被停下来。
知道什么时候在触及上限
看不到的限制只算一半的控制。如果没人能看到上限正在被触及,你既不会注意到正在进行的攻击,也不会注意到正常用户被关在门外。记录限制触发的频率,并在激增时发出告警。这就是组织的安全基线中“能察觉到异常”的状态,在这里的具体应用。
本站的看法:限制的目的是让滥用不划算
把速率限制当作能完全挡住攻击的东西,就会卡在一个无解的问题上:尝试多少次才算安全?我们的看法不同:这是攻击者的成本与收益问题。提高攻击者每次尝试的成本(时间、计算量、CAPTCHA、第二因素),降低每次尝试的预期收益(命中的概率、命中后能走多远)。不必把成功率降到零,只要让它不值得去做。
所以我们更倾向于延迟和第二因素,而不是严厉的锁定。唯一的例外是金钱:唯一可靠的上限,是位于你自己代码之外的费用上限。代码总有出错的时候——在代码之外放一道控制,让错误也不至于产生没有上限的账单。
出处(一手资料)
- NIST SP 800-63B「Digital Identity Guidelines: Authentication and Lifecycle Management」§5.2.2 Rate Limiting (Throttling) — pages.nist.gov(把连续失败限制在100次以内的 SHALL;CAPTCHA、逐渐延长的等待、IP 白名单和基于风险的技术;成功后忽略同一 IP 此前失败次数的 SHOULD)
- OWASP API Security Top 10 2023「API4:2023 Unrestricted Resource Consumption」— owasp.org(需要限制的资源、对成本的影响、设置第三方服务的费用上限)
接下来阅读
- 比较2026年的重大事件:KDDI、Aflac、数字厅和樱花互联网的共同点
- 实际案例:丹麦 CPR 登记系统被滥用(正规客户端的查询权限被滥用)
- 实际案例:Baitoru 泄露事件(最多388万个邮箱地址)(通过“规格缺陷”大量收集,以及按用户的记录数上限)
- 前提:X-Forwarded-For 伪造与可信代理(“按谁计数”的基础)
- 设计:密码重置的设计缺陷 / 如何选择多因素认证
- 成本:密钥被盗、账单和账户被封 / 从 AI 写的代码中泄露的 API 密钥
FAQ
Q登录失败几次应该锁定账户——3次?5次?
NIST SP 800-63B 要求验证方把单个账户的连续认证失败次数限制在100次以内。3次或5次并不是标准的要求。为了避免把正常用户锁在外面,同一份文档要求的是:认证前使用 CAPTCHA、随着接近上限而逐渐延长的等待时间、用户以前认证成功过的 IP 地址白名单,以及基于风险或自适应的技术。激进的锁定还会给攻击者一个故意冻结他人账户的手段。与其只压低次数,不如提高每次尝试的成本。
Q按 IP 地址限制就够了吗?
不够。在反向代理或 CDN 后面,应用看到的地址可能并不是真实来源:无条件信任 X-Forwarded-For,攻击者只要改写一个请求头就成了另一个客户端,你其实什么也没数到。而且正常用户会通过企业 NAT 和移动网络共用地址,所以按 IP 限制也会限制到无关的用户。请把与行为主体绑定的标识——账户、API 密钥、已建立的会话——作为主轴,把 IP 当作辅助信号。
Q怎样防止确认邮件轰炸?
既要限制谁能触发发送,也要统计发往同一目标的数量。如果你的表单接受别人的地址,攻击者就能借你骚扰第三方,同时损害你域名的发信信誉。把按目标地址的冷却时间、重发的最小间隔、以及一定时间内未确认记录的删除结合起来——后者也能减少你持有的未经验证的个人数据。
Q把 AI API 接到公开功能上,最大的危险是什么?
账单。OWASP API Security Top 10 在 API4:2023 Unrestricted Resource Consumption(不受限制的资源消耗)中列出了 API 需要的限制——执行超时、内存、上传大小、每次请求的操作数——并把第三方服务的费用上限也列在其中。它的场景中有账单从每月13美元涨到8,000美元的例子。限制请求次数挡不住单次就很昂贵的操作。请设置服务商一侧的费用上限:这是在你自己的代码出错时仍然有效的那道上限。