4. API安全机制:身份认证、签名算法、IP白名单与访问频率限制
支付风控评分通道直接暴露在公网,任何安全漏洞都可能导致资金损失或敏感数据泄露。本章围绕四道核心防线展开:身份认证确保调用方合法,签名算法防止请求被篡改,IP白名单缩小攻击面,访问频率限制抵御滥用与DDoS。四者缺一不可,构成纵深防御体系。
安全原则:所有API请求必须同时通过身份认证、签名校验、IP白名单和频率限制四道关卡,任一关卡失败则直接拒绝,不返回任何业务数据。
4.1 身份认证:API Key + OAuth2 双模式
风控评分通道支持两种认证模式,适用于不同场景:
| 认证模式 | 适用场景 | 安全等级 | 凭证有效期 |
|---|---|---|---|
| API Key | 服务端到服务端、内部系统、定时任务 | 中 | 长期(可轮换) |
| OAuth2 Client Credentials | 第三方接入、多租户、需要细粒度权限 | 高 | 短期(Access Token 2小时) |
4.1.1 API Key 认证流程
- 商户在控制台生成一对
api_key和api_secret。 - 请求时在 HTTP Header 中携带
X-API-Key: {api_key}。 - 服务端根据
api_key查找对应的api_secret,用于后续签名校验。
# 请求示例
POST /v1/risk/score
Host: api.payrisk.com
X-API-Key: pk_live_abc123def456
Content-Type: application/json
{
"transaction_id": "TXN20250321001",
"amount": 19900,
"currency": "CNY"
}
4.1.2 OAuth2 Client Credentials 流程
- 商户使用
client_id和client_secret调用/oauth/token获取 Access Token。 - 后续请求在 Authorization Header 中携带
Bearer {access_token}。 - Token 过期后需重新获取,避免长期凭证泄露风险。
# 获取 Token
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=merchant_001
&client_secret=secret_xyz789
# 响应
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 7200
}
推荐:对外部第三方接入强制使用 OAuth2,内部系统间通信可使用 API Key + 签名组合,降低 Token 刷新带来的延迟。
4.2 签名算法:HMAC-SHA256 请求防篡改
仅凭 API Key 无法防止请求在传输过程中被篡改。签名算法为每个请求生成唯一指纹,服务端校验指纹一致性,确保请求体、时间戳、路径均未被修改。
4.2.1 签名生成步骤
- 拼接待签名字符串:
HTTP_METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY - 使用
api_secret作为密钥,通过 HMAC-SHA256 计算签名。 - 将签名放入 Header
X-Signature: {signature}。
// 伪代码示例
String message = "POST\n/v1/risk/score\n1711000000\n{\"transaction_id\":\"TXN001\"}";
String signature = HmacSHA256(message, api_secret);
// 输出: 3a7c9f1b2e8d4f6a0c5b3e7d9f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9
4.2.2 服务端校验流程
- 提取 Header 中的
X-Timestamp,检查是否在 ±5 分钟内,防止重放攻击。 - 根据
X-API-Key查找对应的api_secret。 - 使用相同算法重新计算签名,与
X-Signature比对。 - 签名不匹配或时间戳超限,直接返回 401 Unauthorized。
常见错误:签名计算时未包含请求体(Body)或时间戳,导致中间人可篡改请求内容。务必使用完整待签名字符串。
4.3 IP白名单:网络层访问控制
即使 API Key 和签名正确,攻击者仍可能通过窃取凭证发起请求。IP白名单从网络层限制只有特定 IP 地址段可以访问 API。
4.3.1 配置方式
- 商户级别:每个商户可配置最多 10 个 IP 或 CIDR 段(如
192.168.1.0/24)。 - 全局级别:平台运维入口、监控系统等内部服务使用独立白名单。
- 动态更新:通过管理 API 实时增删白名单,无需重启服务。
4.3.2 校验逻辑
// 伪代码:IP白名单校验
function isIpAllowed(clientIp, merchantId):
whitelist = getMerchantIpWhitelist(merchantId)
for cidr in whitelist:
if ipInCidr(clientIp, cidr):
return true
return false
最佳实践:生产环境建议同时配置 IP 白名单和签名校验,形成双重防护。开发测试环境可放宽白名单,但必须保留签名校验。
4.4 访问频率限制:防止滥用与DDoS
即使身份和签名都合法,单个商户的异常高频请求仍可能拖垮风控服务。频率限制按时间窗口和维度进行精细化控制。
4.4.1 限流维度与阈值
| 维度 | 默认阈值 | 时间窗口 | 超出处理 |
|---|---|---|---|
| API Key | 1000 次 | 1 分钟 | 返回 429 Too Many Requests |
| 客户端 IP | 500 次 | 1 分钟 | 返回 429,记录告警 |
| 商户 ID | 10000 次 | 1 小时 | 返回 429,触发风控人工审核 |
4.4.2 滑动窗口算法实现
采用 Redis Sorted Set 实现滑动窗口计数,避免固定窗口的“突刺”问题。
// 滑动窗口限流伪代码
function isRateLimited(key, limit, windowSeconds):
now = currentTimestamp()
windowStart = now - windowSeconds * 1000
// 移除窗口外的旧数据
redis.zremrangebyscore(key, 0, windowStart)
// 统计当前窗口请求数
count = redis.zcard(key)
if count >= limit:
return true // 限流
// 记录当前请求
redis.zadd(key, now, now)
redis.expire(key, windowSeconds)
return false
4.5 安全机制组合策略
四道防线并非独立运行,而是形成协同防御:
- IP白名单 + API Key:即使 API Key 泄露,攻击者若不在白名单内仍无法调用。
- 签名 + 时间戳:防止重放攻击,即使请求被截获也无法重复使用。
- 频率限制 + 告警:单商户异常高频触发告警,自动临时封禁并通知运维。
注意:不要将 API Secret 硬编码在客户端代码或前端页面中。所有凭证应通过环境变量或密钥管理服务(KMS)注入。
4.6 安全配置清单
| 检查项 | 要求 | 验证方式 |
|---|---|---|
| API Key 轮换 | 每 90 天强制轮换一次 | 控制台记录上次轮换时间 |
| 签名算法 | 必须包含时间戳和请求体 | 自动化测试用例覆盖 |
| IP白名单 | 生产环境至少配置 1 个 CIDR | 从非白名单 IP 测试返回 403 |
| 频率限制 | 每个维度阈值不超过默认值 2 倍 | 压测工具模拟超限请求 |