滥用问题

场景

我的 API 平台越来越受欢迎。

两个月后,我去看了监控数据:

那时候的我还不明白,危险正在逼近。

异常发现

某天早上,我收到了外部 API 提供商的邮件:

Inbox
From: 外部 API 提供商
To:
Time: 周三 09:15
Subject: 【重要通知】调用配额异常

我们检测到您的 API 调用异常:

  • 昨天:00:00-06:00,调用量异常
  • 6 小时内调用了:8000 次
  • 正常情况:全天约 5000 次

请检查是否有异常调用。

如继续异常,我们将暂停服务。

看到邮件的那一刻,我后背发凉:6 小时调用了 8000 次?

这意味着有人在 24 小时内可以消耗我 32000 次配额,而我的免费额度只有 10000 次/天。

调查过程

我赶紧查看日志,结果让我震惊:

Top 10 IP:
203.0.113.1: 7500 次  ← 异常!
198.51.100.1: 150 次
198.51.100.2: 120 次
...

发现异常 IP:203.0.113.1

深入分析

我查看了这个 IP 的调用日志:

access.log
$ grep "203.0.113.1" access.log | tail -20 10:00:01 GET /api/weather?city=北京 10:00:01 GET /api/weather?city=上海 10:00:02 GET /api/weather?city=深圳 10:00:02 GET /api/weather?city=广州 10:00:03 GET /api/weather?city=杭州 10:00:03 GET /api/weather?city=南京

特征:

  • 每秒调用 2-3 次
  • 轮流查询不同城市
  • 持续不断,没有停止

结论:有人在爬取数据!

问题严重性

我计算了一下:

这个爬虫的调用情况:
- 每秒:2-3 次
- 每分钟:约 150 次
- 每小时:约 9000 次
- 每天:约 216000 次

占用的外部 API 配额:
- 我的限额:10000 次/天
- 这个爬虫:216000 次/天
- 影响:会让我的账号被限流!

更糟糕的是:

  • 正常用户无法访问(外部 API 限流)
  • 我的服务不可用
  • 用户开始投诉

那一刻,我真的慌了。

尝试解决

方案 1:封禁 IP

我先把异常 IP 封禁了:

设计流程
方案 1:封禁 IP
  1. 步骤 1:校验调用方身份,并绑定用户、应用和权限范围
  2. 步骤 2:读取 API Key、调用方信息和请求上下文
  3. 步骤 3:根据认证结果、权限和配额决定放行或拒绝
  4. 步骤 4:返回认证结果,并写入审计、配额和异常访问记录
关注点:身份可信度、权限边界、配额消耗和审计追踪。

效果:

  • 这个爬虫被阻止了
  • 但几天后,又出现了新的爬虫 IP

我知道,这是场猫鼠游戏,我追不上。

方案 2:限制单个 IP 的调用频率

设计流程
方案 2:限制单个 IP 的调用频率
  1. 步骤 1:校验调用方身份,并绑定用户、应用和权限范围
  2. 步骤 2:读取 API Key、调用方信息和请求上下文
  3. 步骤 3:根据认证结果、权限和配额决定放行或拒绝
  4. 步骤 4:返回认证结果,并写入审计、配额和异常访问记录
关注点:身份可信度、权限边界、配额消耗和审计追踪。

效果:

  • 限制了单个 IP 的调用频率 ✅
  • 但如果有人用很多个 IP 呢?❌
  • IP 记录越来越多,内存占用增加 ❌

这个方案还是治标不治本。

方案 3:关键问题

那天晚上我在想:为什么任何人都能随意调用我的 API?

问题在于:没有门槛

我需要一种机制来:

  • 识别谁在调用
  • 限制每个用户的调用配额
  • 防止滥用

解决思路

我需要引入用户认证系统。

核心概念:

每个用户注册 → 获得唯一的 API Key
每次调用 → 必须携带 API Key
根据 API Key → 识别用户身份、限制配额
┌─────────────┐
│  开发者     │
└──────┬──────┘

       │ 1. 注册

┌─────────────────────┐
│  我的平台           │
│  - 分配 API Key      │
│  - 设置调用配额     │
└──────┬──────────────┘

       │ 2. 调用 API (携带 API Key)

┌─────────────────────┐
│  验证 API Key        │
│  - 检查是否有效     │
│  - 检查配额         │
└──────┬──────────────┘

       │ 3. 返回数据

┌─────────────┐
│  成功/失败  │
└─────────────┘

这是最彻底,但也最复杂的方案。

作为 solo founder,我的时间有限。但我明白,有些路再难走也要走。

我决定:干。