3. 支付系统安全接入基础:HTTPS、签名、加密、防重放攻击
支付系统是金融交易的核心枢纽,其安全接入是抵御中间人攻击、数据篡改、重放攻击等威胁的第一道防线。本章将深入剖析 HTTPS 双向认证、请求签名、敏感数据加密以及防重放机制这四大安全基石,帮助你在 OAuth2.0 中间件与支付订单系统的集成中构建纵深防御体系。
3.1 HTTPS 双向认证:通信信道的基石
支付系统要求通信双方(商户客户端 ↔ 支付网关)不仅验证服务器身份,还需验证客户端身份,即 双向 TLS(mTLS)。这确保了信道加密且身份可信。
| 对比项 | 单向 HTTPS | 双向 HTTPS (mTLS) |
|---|---|---|
| 验证方向 | 客户端验证服务器证书 | 客户端与服务器互相验证证书 |
| 客户端证书 | 不需要 | 必须持有合法客户端证书 |
| 安全等级 | 防止服务器伪造 | 防止服务器伪造 + 防止客户端伪造 |
| 支付场景 | 信息查询、非敏感操作 | 交易下单、退款、敏感信息查询 |
3.2 请求签名:防篡改与身份认证
即使信道加密,支付请求在到达网关前仍可能被应用层篡改。请求签名机制通过哈希算法和私钥对请求参数进行签名,确保数据完整性和请求来源的不可抵赖性。
3.2.1 签名生成流程
- 参数排序:将请求参数(除签名本身外)按字典序升序排列。
- 拼接字符串:将排序后的参数以
key=value格式拼接,中间用&连接。 - 附加密钥:在拼接字符串末尾追加商户密钥(API Secret)。
- 计算摘要:使用 HMAC-SHA256 或 RSA-SHA256 算法计算摘要,并转为十六进制字符串。
// 示例:HMAC-SHA256 签名生成(Java 伪代码)
String sortedParams = "amount=100.00&merchant_id=M2024001&order_id=ORD20241001001×tamp=1727740800";
String rawString = sortedParams + "&key=" + apiSecret;
String signature = HmacSHA256(rawString, apiSecret);
// 输出:a1b2c3d4e5f6...
3.2.2 验签流程
支付网关收到请求后,使用相同的算法和商户密钥重新计算签名,并与请求中的 sign 字段比对。若不一致,直接拒绝请求并返回签名错误。
3.3 敏感数据加密:字段级保护
支付请求中常包含银行卡号、CVV、身份证号等敏感信息。即使信道加密,支付网关内部处理时仍需对敏感字段进行二次加密,实现 端到端加密。
| 加密类型 | 算法 | 用途 | 密钥管理 |
|---|---|---|---|
| 对称加密 | AES-256-GCM | 加密请求体中的敏感字段 | 支付网关与商户协商的对称密钥 |
| 非对称加密 | RSA-2048 / ECC P-256 | 加密对称密钥或小数据量敏感信息 | 商户持有公钥,网关持有私钥 |
| 混合加密 | RSA + AES | 用 RSA 加密 AES 密钥,用 AES 加密数据 | 兼顾安全性与性能 |
3.4 防重放攻击:时间戳与 Nonce
攻击者截获一次合法的支付请求后,若系统无防重放机制,可反复发送该请求,导致用户被多次扣款。防重放攻击的核心是确保每个请求 唯一且仅在有效期内有效。
3.4.1 时间戳校验
请求中携带 timestamp 字段(Unix 时间戳,秒级)。网关收到请求后,计算当前时间与 timestamp 的差值,若超过允许的时间窗口(通常为 5 分钟),则判定为过期请求并拒绝。
3.4.2 Nonce 机制
请求中携带 nonce 字段(一次性随机字符串)。网关在处理请求前,先检查 Redis 或数据库中存在该 nonce。若已存在,说明是重放请求,直接拒绝;若不存在,则将其存入缓存并设置过期时间(与时间窗口一致)。
// 防重放校验伪代码
function isReplayAttack(timestamp, nonce) {
// 1. 时间窗口校验
if (abs(now() - timestamp) > 300) return true;
// 2. Nonce 唯一性校验
if (redis.exists(nonce)) return true;
// 3. 存储 Nonce,设置 5 分钟过期
redis.setex(nonce, 300, "used");
return false;
}
3.5 安全接入架构总览
下图展示了支付系统安全接入的完整流程,涵盖 HTTPS 双向认证、签名、加密与防重放四大机制在请求生命周期中的位置。
3.6 安全接入检查清单
在集成支付系统时,请逐项核对以下安全要点:
- HTTPS:是否已配置双向 TLS?客户端证书是否已绑定 IP/域名白名单?
- 签名:签名算法是否为 HMAC-SHA256 或 RSA-SHA256?API Secret 是否存储在服务端?
- 加密:敏感字段是否使用了混合加密?AES 密钥是否每次请求随机生成?
- 防重放:时间窗口是否设置为 5 分钟以内?Nonce 是否在 Redis 中原子性存储?
- 日志:是否记录了签名、加密、Nonce 校验的失败日志?是否对敏感字段进行了脱敏?