# 短信、OTP 与付费接口

> 在滥用请求变成账单之前拦住它们。

工程防护 · /zh/otp/ · 2026-11-05

攻击者可以用脚本批量调用公开的发送接口，而应用看起来一切正常。损失体现在账单上，往往流量停了以后才发现。

## 让 AI agent 审查付费调用

**Prompt**

```text
审查 [Jira 编号、PR 链接或 diff] 是怎么调用付费服务商的。
如果是 Jira ticket，通过已连接的 Jira MCP 或已认证的 acli 读取描述、验收标准和评论；无法访问时，让我粘贴详情。
把每个付费调用从请求检查一路追到服务商调用和费用记账。用 mock 或测试服务，对照本页的要求检查限流、消费上限、kill switch 和告警。
逐条报告可以绕过的地方，附上证据。
说明本页列出的测试哪些已在项目测试套件里。能自动化的补上，其余的列出来。
不要发送真实消息，也不要产生费用。
```

## 发送前检查请求

图示: 发送短信之前：服务端校验的人机验证、限流、目的国家白名单、kill switch 和强制执行的消费上限。发送之后监控验证率。

_每项检查都在付费发送之前执行；发送之后监控验证率。_

- **OTP-1** (高风险; 由测试检查): **公开的 OTP 接口发送验证码前，必须在服务端校验人机验证结果。** 只在客户端检查，可以被绕过。
- **OTP-2** (高风险; 由测试检查): **每个维度都要限流。** 按手机号、IP、设备和账号分别限流，另加每分钟和每天的全局上限。

  注意: 在调用服务商之前检查限流，重发也一样。
- **OTP-3** (高风险; 由测试检查): **只发往产品提供服务的国家。** 其他国家的请求在到达服务商之前就拒绝。

  注意: 国家从解析后的手机号里取，不要用客户端可控的国家选择器。

* 先规范化手机号，再做限流。计数器在并发的 worker 之间必须一致。无法完成限流检查时，就不发送。
* 限流要在应用里做。负载均衡或 CDN 的限流有帮助，但只有应用知道手机号、账号和设备。
* 客户端 IP 只从可信代理设置的 header 里取，不要用客户端能伪造的 header。否则负载均衡后面的所有用户共用一个 IP，按 IP 的限流要么拦住所有人，要么谁都拦不住。
* 重发间隔在服务端控制：例如 30 秒、60 秒、5 分钟，之后暂停一小时。实际限额按预期流量来定，并记录在仓库里。
* 不管账号是否存在，对外返回相同的响应；具体的拒绝原因记在内部指标里。

## 限制花费并监控验证率

- **OTP-4** (高风险; 由应用本身和测试检查): **付费调用之前检查硬性消费上限，超了就不发。** 所有 worker 共用一份预算，用原子操作扣减。服务商提供的消费上限、告警和反欺诈功能也要开启；光有告警拦不住花费。

  注意: 服务商的控制是应用限额的补充；确认哪些设置真的会拦截请求。
- **OTP-6** (高风险; 由测试检查): **kill switch 不需要部署就能停止所有发送。**
- **OTP-5** (中风险; 由测试检查): **验证率下降时告警：** 验证率是同一时间窗口内验证成功的验证码数除以发出的验证码数。下降时要排查滥用、投递失败和验证流程故障。

* 超时的发送仍可能被计费。在服务商确认结果之前，保留它占用的预算；[超时只说明结果未知](/zh/value-abuse/#r-val-6)。

> **失败案例 (示意): 安静的周六**
>
> 周末，发往服务范围之外国家的短信涨到平时的三倍，几乎没有验证码完成验证。目的国家白名单本可以拦下这些发送；即使攻击者把请求分散到大量号码上，消费上限也能控制住账单。

## 其他付费 API 也要设费用限制

- 邮件、语音、地图、KYC 和模型调用，都需要按业务流程做调用方鉴权或防滥用检查，并设置按调用方的配额、全局费用上限和 kill switch。
- 手机号验证还要加上国家和验证率控制。其他 API 则要把费用与成功完成的业务结果对照。
- 服务商的凭据只放在服务端；调用服务商时按[后台任务与外部调用](/zh/jobs/#call-external-services-safely)的做法来：显式超时，只在安全时重试，统一限流。

## 测试这些限制

- [ ] **OTP-T1**: 同一号码一分钟内发起 100 次请求，实际发送数不超过限额。
- [ ] **OTP-T2**: 发往白名单以外国家的请求被拒绝，且没有调用服务商。
- [ ] **OTP-T3**: 在 staging 打开 kill switch，一分钟内停止发送。
- [ ] **OTP-T4**: 模拟一次验证率下降，验证率告警会触发。
- [ ] **OTP-T5**: 用并发请求把消费预算用完：没有任何 worker 超出上限多发。
- [ ] **OTP-T6**: 让限流存储不可用：不会调用服务商。
- [ ] **OTP-T7**: 分别带一个无效的人机验证 token、不带 token、绕过前端直接请求后端：三种情况都走不到付费发送。
