3. 数据传输安全模型:传输层安全(TLS/mTLS)、应用层签名、端到端加密、防重放攻击机制
在多租户签名链路中,数据从客户端发起、经过网关、路由至签名服务,最终落库或回调,每一跳都存在被窃听、篡改、重放或中间人攻击的风险。本章构建四层纵深防御模型,确保数据在传输过程中的机密性、完整性、真实性与时效性。
3.1 四层安全模型总览
安全模型从下至上分为传输层、应用层、数据层与抗重放层,每层解决不同维度的威胁:
| 层级 | 协议/机制 | 核心能力 | 防御目标 |
|---|---|---|---|
| 传输层 | TLS 1.3 / mTLS | 信道加密、双向证书认证 | 防窃听、防中间人、防伪造服务端 |
| 应用层 | HTTP Signature / JWS | 请求签名、消息摘要 | 防篡改、防抵赖、端到端身份验证 |
| 数据层 | 端到端加密(E2EE) | 负载级加密(如使用租户公钥加密) | 防服务端窥探、防数据库泄露 |
| 抗重放 | Nonce + Timestamp + 签名绑定 | 请求唯一性校验、时间窗口验证 | 防重放攻击、防请求克隆 |
设计原则:四层独立但协同。传输层解决信道安全,应用层解决请求真实性,数据层解决内容机密性,抗重放层解决时效性。任何一层被绕过,其他层仍能提供兜底防护。
3.2 传输层安全:TLS 与 mTLS
传输层是安全模型的基石。在多租户场景中,我们推荐使用 TLS 1.3 作为默认协议,并在网关与核心服务之间启用 mTLS(双向 TLS)。
3.2.1 TLS 1.3 核心优势
- 1-RTT 握手:相比 TLS 1.2 的 2-RTT,延迟更低,适合高频签名请求。
- 前向安全性:所有会话密钥通过临时 DH 协商生成,即使长期私钥泄露,历史会话也无法解密。
- 移除不安全算法:强制使用 AEAD 加密(AES-GCM / ChaCha20-Poly1305),禁用 RC4、CBC 模式等脆弱算法。
3.2.2 mTLS 双向认证
在网关与签名服务之间、签名服务与密钥管理服务(KMS)之间,要求双方出示证书。网关只信任由内部 CA 签发的客户端证书,拒绝未认证的调用。
租户隔离提示:mTLS 的客户端证书中可嵌入租户 ID(通过 Subject Alternative Name 或自定义 OID),网关在 TLS 握手阶段即可提取租户身份,避免后续请求中重复解析。
3.3 应用层签名:HTTP Signature 与 JWS
传输层只保护信道,无法防止合法节点内部的篡改。应用层签名对请求的 关键头部 + 负载 进行数字签名,确保端到端的完整性验证。
3.3.1 签名覆盖范围
- 必签字段:HTTP Method、URI、Host、Content-Digest(负载哈希)、Date、Authorization(租户令牌)。
- 可选字段:X-Request-Id、X-Tenant-Id、Nonce。
- 签名算法:推荐使用 Ed25519 或 ECDSA P-384,避免使用 RSA 以降低签名体积。
3.3.2 签名验证流程
- 接收方提取请求中的签名头部(Signature-Input 和 Signature)。
- 根据 Signature-Input 中声明的覆盖字段列表,重新计算签名基串(signature base)。
- 使用发送方公钥(从租户密钥库获取)验证签名。
- 验证 Content-Digest 与请求体哈希是否一致。
常见陷阱:不要只签名请求体而忽略头部。攻击者可以篡改 Host 或 Date 字段,将请求重定向到不同租户的签名上下文。必须将租户标识(X-Tenant-Id)纳入签名范围。
3.4 端到端加密(E2EE)
即使传输层加密且应用层签名,签名服务本身仍能读取明文负载。对于高敏感场景(如金融合同、个人隐私数据),需要引入端到端加密:客户端使用租户专属公钥加密负载,签名服务仅做签名操作,无法解密内容。
3.4.1 加密方案
| 组件 | 密钥 | 用途 |
|---|---|---|
| 客户端 | 租户公钥(从 KMS 获取) | 加密签名请求负载 |
| 签名服务 | 无解密密钥 | 仅对密文进行签名,不接触明文 |
| 验签方 | 租户私钥 | 解密负载并验证签名 |
3.4.2 加密流程
- 客户端生成对称密钥(AES-256-GCM),加密负载。
- 使用租户 RSA-OAEP 或 ECIES 公钥加密该对称密钥。
- 将加密后的对称密钥 + 密文 + 签名一并发送。
- 签名服务对密文进行签名,不接触明文。
- 验签方使用租户私钥解密对称密钥,再解密负载。
性能优化:混合加密(Hybrid Encryption)避免直接使用非对称加密大负载。对称加密速度快,非对称加密仅用于保护对称密钥,适合高频签名场景。
3.5 防重放攻击机制
即使请求被签名且加密,攻击者仍可截获合法请求并重复发送(重放攻击),导致重复签名、重复扣费或状态混乱。防重放机制通过 Nonce + Timestamp + 签名绑定 实现。
3.5.1 核心要素
- Nonce(一次性随机数):每次请求生成唯一值,服务端记录已使用的 Nonce,拒绝重复。
- Timestamp(时间戳):请求发起时间,服务端检查是否在允许的时间窗口内(通常 ±5 分钟)。
- 签名绑定:Nonce 和 Timestamp 必须参与应用层签名,防止篡改。
3.5.2 验证逻辑
// 伪代码:防重放验证
function isReplay(request):
// 1. 时间窗口检查
if abs(now - request.timestamp) > MAX_AGE_SECONDS:
return true // 超时,视为重放
// 2. Nonce 唯一性检查(使用 Redis 或分布式缓存)
if redis.exists("nonce:" + request.nonce):
return true // Nonce 已使用,重放
// 3. 记录 Nonce,设置 TTL 为 MAX_AGE_SECONDS
redis.set("nonce:" + request.nonce, "used", TTL=MAX_AGE_SECONDS)
// 4. 验证签名(包含 nonce 和 timestamp)
if !verifySignature(request):
return true // 签名无效
return false // 通过
分布式环境注意:Nonce 去重需要原子操作,推荐使用 Redis SET NX 或数据库唯一索引。时间窗口不宜过短(避免时钟偏差),也不宜过长(增加 Nonce 存储压力)。建议默认 5 分钟。
3.6 四层模型协同工作流
以下 SVG 展示了完整请求从客户端到签名服务的四层安全处理流程:
3.7 安全模型对比总结
| 安全层 | 保护范围 | 密钥管理 | 性能影响 | 租户隔离粒度 |
|---|---|---|---|---|
| TLS / mTLS | 信道(一跳) | 证书管理(CA 签发) | 低(硬件加速) | 连接级(通过证书 SAN) |
| 应用层签名 | 请求端到端 | 租户密钥对(KMS 管理) | 中(签名运算) | 请求级(签名绑定租户 ID) |
| 端到端加密 | 负载内容 | 租户公钥/私钥 | 中(混合加密) | 数据级(租户专属密钥) |
| 防重放 | 请求唯一性 | 无(Nonce 存储) | 低(Redis 查询) | 请求级(Nonce 绑定租户) |
实施建议:不要试图一次性启用所有层。建议按以下顺序逐步加固:
1. 先部署 TLS 1.3 + mTLS(基础信道安全)。
2. 再引入应用层签名(防篡改与防抵赖)。
3. 对高敏感租户开启 E2EE(数据机密性)。
4. 最后全局启用防重放机制(请求唯一性)。
每增加一层,需评估对延迟和运维复杂度的影响。
1. 先部署 TLS 1.3 + mTLS(基础信道安全)。
2. 再引入应用层签名(防篡改与防抵赖)。
3. 对高敏感租户开启 E2EE(数据机密性)。
4. 最后全局启用防重放机制(请求唯一性)。
每增加一层,需评估对延迟和运维复杂度的影响。