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 认证流程

  1. 商户在控制台生成一对 api_key 和 api_secret。
  2. 请求时在 HTTP Header 中携带 X-API-Key: {api_key}。
  3. 服务端根据 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 流程

  1. 商户使用 client_id 和 client_secret 调用 /oauth/token 获取 Access Token。
  2. 后续请求在 Authorization Header 中携带 Bearer {access_token}。
  3. 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 签名生成步骤

  1. 拼接待签名字符串:HTTP_METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + BODY
  2. 使用 api_secret 作为密钥,通过 HMAC-SHA256 计算签名。
  3. 将签名放入 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)或时间戳,导致中间人可篡改请求内容。务必使用完整待签名字符串。
签名校验流程图 客户端 拼接待签名字符串 HMAC-SHA256 计算 发送请求 服务端 提取 Key/Timestamp 重新计算签名 比对签名 时间戳超限或签名不匹配 → 直接返回 401,不返回业务数据

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
四道安全防线执行顺序 ① IP白名单 网络层过滤 ② 身份认证 API Key / OAuth2 ③ 签名校验 HMAC-SHA256 ④ 频率限制 滑动窗口 执行顺序说明 IP白名单最先执行,拒绝非授权IP,减少后续认证压力 身份认证 → 签名校验 → 频率限制,逐层过滤非法请求

4.5 安全机制组合策略

四道防线并非独立运行,而是形成协同防御:

  • IP白名单 + API Key:即使 API Key 泄露,攻击者若不在白名单内仍无法调用。
  • 签名 + 时间戳:防止重放攻击,即使请求被截获也无法重复使用。
  • 频率限制 + 告警:单商户异常高频触发告警,自动临时封禁并通知运维。
注意:不要将 API Secret 硬编码在客户端代码或前端页面中。所有凭证应通过环境变量或密钥管理服务(KMS)注入。

4.6 安全配置清单

检查项 要求 验证方式
API Key 轮换 每 90 天强制轮换一次 控制台记录上次轮换时间
签名算法 必须包含时间戳和请求体 自动化测试用例覆盖
IP白名单 生产环境至少配置 1 个 CIDR 从非白名单 IP 测试返回 403
频率限制 每个维度阈值不超过默认值 2 倍 压测工具模拟超限请求