安全
鉴权只有 key 一条路径
Section titled “鉴权只有 key 一条路径”契约里只定义了两个安全方案,而且两者携带的是同一个密钥:
| 方案 | 请求头 | 说明 |
|---|---|---|
ApiKeyHeader | X-API-Key | 推荐。 |
BearerAuth | Authorization: Bearer | 等价。当客户端库只接受 bearer token 时使用。 |
两种形式解析出来的是同一份凭据。GET /v1/products 是唯一允许不带鉴权调用的接口。
这里没有 IP 白名单。按 IP 的限流是所有共用同一出口地址的流量共享的上限 —— 它约束滥用,不授予或拒绝访问。请把 key 当作你账户权限边界的全部。
关于 key
Section titled “关于 key”Zelnum 的 API key 是 ck_ 加 48 个字符:共 51 位。比这短的不是 key —— 当密钥管理器把值弄坏时,这是个有用的自检。
| 要 | 不要 |
|---|---|
| 放在密钥管理器或环境变量里 | 放进仓库、任何用户可读的配置文件,或 CI 日志 |
| 从你的服务器发出 | 放进浏览器 JavaScript、移动端包体,或任何公开客户端 |
需要指明是哪个 key 时读 api_key_id | 把 key 本身粘进支持请求 |
| 在日志里打码 | 记录完整请求头 |
打进前端包体的 key 不是密钥。如果某个集成需要从浏览器调用接口,应该由浏览器调你自己的服务器,key 留在你的服务器上 —— 对未鉴权流量更紧的 IP 上限救不了你。
数据库里存的只是 SHA-256 哈希和一个 9 位展示前缀,从不存明文本身,所以即使数据库被拖走也拿不到可用的 token。代价是没有任何接口能取回你的 key:弄丢了只能轮换。
确认当前生效的是哪个 key
Section titled “确认当前生效的是哪个 key”curl -X GET "https://api.zelnum.com/api/v1/api-key" \ -H "X-API-Key: YOUR_KEY_HERE"响应里有 api_key_id、masked_key、last_used 和 created_at —— 对应账户上最近签发且处于启用状态的那个 key。该接口只报一个 key,所以请把它读作「我现在用的会是哪一个」,而不是一份清单。要看全部 key,请到控制台。
last_used 是确认轮换是否真的生效的最快方式,但有一个前提:每个 key 的该字段最多每五分钟写一次。因此一个正在被频繁使用的 key,在你切过去之后最长五分钟内仍可能显示为「从未使用」。不要仅凭 last_used 没动就断定部署坏了。
轮换 key
Section titled “轮换 key”账户可以同时持有多个启用中的 key,控制台对它们逐个管理:
| 控制台操作 | 效果 |
|---|---|
| 创建 | 新增一个 key,已有的 key 全部继续可用。 |
| 重新生成 | 让那一个 key 失效,并签发一个同名替身。原 key 立即停止工作。 |
| 删除 | 直接移除一个 key。 |
由此有两种轮换形态,区别在于你是否承受得起一段重叠窗口。
新建第二个 key —— 分段轮换,也是优先推荐的做法:
- 创建新 key。其他什么都不变,旧 key 仍能通过鉴权。
- 预置新值到所有需要它的地方 —— 应用服务器、worker、定时任务、计划脚本 —— 但先不启用。
- 切换部署。观察
GET /v1/api-key直到它报出新的api_key_id,并把last_used五分钟的写入粒度算进去。 - 删除旧 key,确认已无任何调用方在使用它。这一步才是真正移除凭据的动作 —— 没删就不算轮换完成。
原地重新生成 —— 当旧值必须立刻作废时:
在一个 key 已经泄露、它继续有效的每一分钟都是风险时使用。
- 接受空档。 旧 key 在你重新生成的那一刻就停止工作,因此所有还持有它的组件都会返回
401 unauthorized,直到重新部署。这是刻意设计成没有重叠的。 - 重新生成,并立刻把横幅上的明文值抄走 —— 它只在那里出现一次,之后再也取不回。
- 部署新值,然后确认没有任何组件还在记录
401。
所有接口都是 HTTPS。没有明文监听,也没有任何接口接受降级,所以不存在 key 以明文传输的配置。
如果你在接口前面加代理或网关,请在边缘终结 TLS 并转发 X-API-Key 请求头 —— 不要改写它,也不要把它写进入站请求日志。
你发送了什么、会被保留多久
Section titled “你发送了什么、会被保留多久”接口的输入是手机号与邮箱地址 —— 在多数司法辖区属于个人数据。两个推论:
- 只发需要的东西。 一次检测需要标识本身,别的都不需要。不要在请求体里塞用户 ID、内部编号或自由文本元数据:它们不会被存成字段,只会扩大你自己日志的暴露面。
- 清楚保留期。 实时日志与幂等重放结果默认保留 30 天,批量结果文件 7 天(由
result_retention_days控制)。过了窗口记录就没了,所以需要留存的必须自己导出。
在你自己的系统里也要把号码当作敏感数据。一条检测结果会告诉旁观者某个具体的人是否注册在某个具体平台上,而「标识 + 结论」这一对信息比其中任何一半都更具揭示性。
这既是安全属性也是计费属性:Idempotency-Key 让重试变得安全,所以网络抖动或手快的人都不会把一次扣费变成两次。绝不要为了让一个你没观察到结果的请求重试而生成新的 key —— 见幂等与重试。