采集任务的 API Key 管理:轮换、止损、最小暴露的工程实践
我踩过最惊险的一个坑:一次调试临时把 API Key 写进了脚本里,顺手 git 提交。两天后才发现。对这个接口来说 Key 就是「预付费余额的钥匙」——被人拿去刷,烧的是我的 credits。连夜轮换之后,我把 Key 管理整理成了几条硬规则。这篇记录 Key 管理的工程实践。
四条基本规则
- 一个环境一个 Key:开发、测试、生产分开。测试把生产余额跑光的事故,很多就是这么来的。
- Key 只在服务端:环境变量或密钥管理服务,绝不进浏览器、App、公开仓库。
- 最小暴露:不给不需要的人 full access 的 Key;临时协作发临时 Key,用完回收。
- 可轮换:代码里读 Key 的路径统一(
os.environ["SERPBASE_API_KEY"]),轮换时只改配置和部署,不改代码。
轮换的标准流程
轮换不是「把旧的删了换个新的」——那样必然有停机窗口。标准顺序:
1. 申请新 Key(旧 Key 保持有效)
2. 更新配置/部署,让新 Key 生效
3. 观察新 Key 的请求全部成功(看日志里的 request_id 都正常)
4. 确认旧 Key 没有流量后,吊销旧 Key
5. 记录轮换时间 + 原因到运维日志
关键是「新旧并存的过渡期」——先切后废,采集不中断。
泄露止损清单
万一 Key 泄露了(进了 git、日志、前端),按这个顺序处理:
- 立即吊销:先断血,别先追责
- 看用量异常:对比平时的请求量和 credits 消耗曲线,确认有没有被刷
- 换新 Key:按上面的轮换流程
- 清理泄露点:git 历史、日志文件、前端构建产物
- 复盘:泄露路径是什么,加什么检查防止下次
平时请求量和余额消耗应该是平稳曲线——接口响应里的 credits_charged 落库统计后,异常会一眼看出来,这是最早期的预警信号。计费字段的说明在 SerpBase 官方文档 里有。
代码层面的防泄漏
import os, hashlib
API_KEY = os.environ["SERPBASE_API_KEY"]
def mask(key: str) -> str:
# 日志里永远只打掩码,不打完整 Key
return key[:6] + "..." + hashlib.md5(key.encode()).hexdigest()[:6]
logger.info("using api key %s", mask(API_KEY))
三条代码纪律:
- Key 从环境变量读,不写在代码里
- 日志打掩码,不打原文(很多人栽在调试日志里)
- Key 放请求头(如
X-API-Key),不放 URL 参数——URL 会进访问日志、进监控、进 referer
踩坑记录
坑 1:Key 进了 git 历史。 删掉文件不算完,历史里还在。处理:吊销 + 换新 +(必要时)清历史;预防:提交前扫描 + .gitignore + 把 Key 从示例文件里拿掉。
坑 2:Key 进了日志。 调试时 print(headers) 把完整 Key 打进了日志文件,日志还会被收集和转发。日志里只允许掩码。
坑 3:一个 Key 全局用。 本地测试、线上采集、临时脚本共用一个 Key。测试跑飞直接烧线上余额。按环境分开。
坑 4:轮换只做了「换」,没做「废」。 新 Key 上线了,旧 Key 忘了吊销,躺了半年还能用。轮换流程最后一步必须是吊销确认。
坑 5:泄漏后先排查后止损。 花两小时查「怎么泄的」,期间还在被刷。顺序反过来:先吊销断血,再慢慢查。
工程清单
- 按环境分 Key,Key 只在服务端
- 统一从环境变量读取,轮换不改代码
- 先切新、后废旧的零停机轮换
- 日志只打掩码,Key 走请求头不走 URL
- 泄露止损:先吊销,再看用量,最后复盘
- 用
credits_charged做余额消耗曲线,异常早发现
Key 管理的本质是两件事:平时让它藏得住,出事让它断得快。藏得住靠纪律(环境变量、掩码、分环境),断得快靠流程(先切后废、吊销优先)。这两样都不复杂,但能挡住最贵的那类事故。
接口的鉴权方式(请求头 X-API-Key)和计费字段说明在 SerpBase 官方文档。你们的采集 Key 是几个环境共用的?评论区聊聊。

浙公网安备 33010602011771号