AI API 请求签名与防重放攻击实战指南:保护你的中转站密钥不被盗刷
2026-09-02 · 约 10 分钟阅读
本文是一篇方法论/工程实践类的常青内容,不依赖任何易变的模型版本或定价信息,聚焦一个所有使用 AI API 中转站的开发者都应该重视的安全议题:如何通过请求签名机制,让即使 API Key 被截获,攻击者也无法直接盗刷你的额度。
为什么只靠 API Key 不够安全
多数 AI API(包括中转站)的默认认证方式是在请求头里携带一个静态的 API Key(如 Authorization: Bearer sk-xxx)。这种方式简单,但有明显的风险:
1. 一旦 Key 泄露(比如被打包进前端代码、误传到公开仓库),攻击者可以无限次直接调用,只要 Key 有效就能一直盗刷额度
2. 中间人攻击或日志泄露场景下,请求本身可能被完整截获并重放,即使你后续换了 Key,历史请求如果被保存下来,攻击者仍可能尝试重放
3. 纯 Key 认证无法验证请求内容是否被篡改,如果中间环节被劫持修改了请求参数,服务端无法感知
请求签名机制的核心思路是:每次请求除了携带 Key,还要附带一个基于请求内容动态计算出的签名,签名会随时间和内容变化,即使被截获也无法直接复用。
HMAC 签名机制设计
最常见的方案是用 HMAC-SHA256 对请求关键信息做签名,服务端用同样的密钥重新计算一遍,比对签名是否一致。
import hmac
import hashlib
import time
import json
import uuid
def generate_signature(secret_key: str, method: str, path: str, body: dict, timestamp: int, nonce: str) -> str:
"""
生成请求签名
签名内容包含:HTTP方法 + 路径 + 请求体 + 时间戳 + nonce
任何一项被篡改,签名都会失效
"""
body_str = json.dumps(body, sort_keys=True, separators=(",", ":")) if body else ""
sign_string = f"{method.upper()}\n{path}\n{body_str}\n{timestamp}\n{nonce}"
signature = hmac.new(
secret_key.encode("utf-8"),
sign_string.encode("utf-8"),
hashlib.sha256
).hexdigest()
return signature
def build_signed_request(api_key: str, secret_key: str, path: str, body: dict) -> dict:
timestamp = int(time.time())
nonce = str(uuid.uuid4())
signature = generate_signature(secret_key, "POST", path, body, timestamp, nonce)
headers = {
"Authorization": f"Bearer {api_key}",
"X-Timestamp": str(timestamp),
"X-Nonce": nonce,
"X-Signature": signature,
}
return headers
调用方在发起请求时附带这些额外的 header,服务端(如果是自建的中转/网关层)用相同算法验证:
def verify_signature(secret_key: str, method: str, path: str, body: dict,
timestamp: int, nonce: str, received_signature: str,
max_time_drift: int = 300) -> bool:
# 第一步:时间窗口校验,防止旧请求被长期重放
current_time = int(time.time())
if abs(current_time - timestamp) > max_time_drift:
return False # 超出允许的时间偏差(比如 5 分钟),拒绝
# 第二步:重新计算签名并比对
expected_signature = generate_signature(secret_key, method, path, body, timestamp, nonce)
# 使用恒定时间比较,避免时序攻击泄露签名信息
return hmac.compare_digest(expected_signature, received_signature)
Nonce 防重放:同一个签名不能用第二次
只做时间窗口校验还不够——在窗口期内(比如 5 分钟内),同一个请求理论上仍然可以被重放一次。加入 Nonce(一次性随机数)机制,配合服务端缓存已使用过的 nonce,可以从根本上防止重放:
import redis
r = redis.Redis()
def check_nonce_not_reused(nonce: str, timestamp: int, max_time_drift: int = 300) -> bool:
"""检查这个 nonce 是否已经被使用过,未使用则标记为已用"""
cache_key = f"nonce:{nonce}"
# SETNX:仅当 key 不存在时设置成功,天然实现"检查并标记"的原子操作
is_new = r.set(cache_key, "1", nx=True, ex=max_time_drift + 60)
return bool(is_new) # True 表示第一次见到这个 nonce,可以放行
def full_verify(secret_key, method, path, body, timestamp, nonce, signature):
if not verify_signature(secret_key, method, path, body, timestamp, nonce, signature):
return False, "签名无效或已过期"
if not check_nonce_not_reused(nonce, timestamp):
return False, "检测到重放请求,拒绝处理"
return True, "验证通过"
Node.js 实现版本
const crypto = require("crypto");
function generateSignature(secretKey, method, path, body, timestamp, nonce) {
const bodyStr = body ? JSON.stringify(body) : "";
const signString = `${method.toUpperCase()}\n${path}\n${bodyStr}\n${timestamp}\n${nonce}`;
return crypto
.createHmac("sha256", secretKey)
.update(signString)
.digest("hex");
}
function buildSignedHeaders(apiKey, secretKey, path, body) {
const timestamp = Math.floor(Date.now() / 1000);
const nonce = crypto.randomUUID();
const signature = generateSignature(secretKey, "POST", path, body, timestamp, nonce);
return {
Authorization: `Bearer ${apiKey}`,
"X-Timestamp": String(timestamp),
"X-Nonce": nonce,
"X-Signature": signature,
};
}
实战注意事项
1. 时间窗口不宜设置过长:5 分钟是常见的折中值,太短容易因为客户端和服务端时钟不同步导致正常请求被误判,太长则给重放攻击留出更大的可利用窗口
2. 签名密钥(secret_key)和 API Key 应该分离管理:即使 API Key 意外泄露,只要签名密钥不泄露,攻击者依然无法伪造有效签名
3. 前端场景不建议直接嵌入签名密钥:如果是纯前端应用(无后端中转),签名密钥同样会暴露在客户端代码里,这种场景应该把签名计算放在你自己的后端服务上,前端只和你的后端交互,你的后端再代理调用 AI API 中转站
4. 多数第三方 AI API 中转站不原生支持自定义签名协议:这套机制更适合用在"你自己的后端服务"和"你的前端/客户端"之间,中转站到你后端之间仍然用标准的 API Key 认证,但你的后端由你自己控制,可以严格限制调用来源和频率
总结
请求签名和防重放机制不是所有场景都必须上,但对于面向公开客户端(比如移动 App、小程序、SDK)分发的应用来说,是防止 API Key 被截获后被无限盗刷的重要一层防护。核心设计原则是:签名内容要覆盖关键请求参数、时间窗口要合理、Nonce 要配合服务端存储做唯一性校验。三者结合,能在不影响正常业务的前提下,大幅提高盗刷的技术门槛。
如果你在为 AI 应用寻找计费透明、支持精细化用量控制的中转站,可以前往 openairouter.net 中转站排行榜 查看对比,选择更适合你安全需求的平台。