✅ 签名机制笔记(按 SK 存储位置划分)
一、签名的本质
签名是一种使用密钥(SK)和请求参数通过加密算法生成摘要的机制,目的是:
-
防止数据被篡改
-
验证请求来源是否合法
-
防止重放攻击
二、两种主流签名方案分类(按 SK 存储位置)
方案名称 | SK 存储位置 | 客户端是否签名 | 服务端是否签名 | 特点 |
---|---|---|---|---|
🧠 方案一:客户端持有SK | 客户端 | ✅ 是 | ❌ 否 | 签名在客户端生成,服务端验签 |
🔒 方案二:服务端持有SK | 服务端 | ❌ 否 | ✅ 是(两次) | 签名在服务端生成+验证 |
三、方案一:客户端持有 SK(私钥签名)
✅ 流程
-
客户端用 SK(私钥)对请求参数签名
-
客户端发送:
参数 + 签名 + 公钥标识(或 AK)
-
服务端用对应公钥验签
✅ 优点
-
客户端可独立签名
-
服务端无需存 SK,只需公开公钥
⚠️ 缺点
-
前端私钥极难保护,尤其是浏览器环境
-
一旦私钥泄露,签名形同虚设
-
对客户端安全要求极高(适合原生App + 安全芯片)
四、方案二:服务端持有 SK(签名双流程)
✅ 【完整两步流程】
步骤一:获取签名
-
客户端发送:
AK + 数据参数
→ 签名服务端点 -
服务端根据 AK 找到对应 SK
-
服务端用 SK 对数据签名 → 返回签名给客户端
步骤二:调用实际接口
-
客户端发送:
AK + 参数 + 签名
→ 实际业务接口 -
服务端再次通过 AK 找 SK
-
服务端重新签名 → 比对两个签名 → 验签通过后执行业务
✅ 优点
-
客户端无私钥,前端无密钥泄露风险
-
服务端统一管理密钥,方便轮换和权限控制
-
签名逻辑由服务端控制,更灵活可控
⚠️ 缺点
-
增加一次签名请求(稍微复杂)
-
签名接口需要防止滥用(需鉴权/限流/日志)
-
签名具有时效性,客户端不能缓存太久
五、两种方案对比
对比项 | 客户端持有 SK | 服务端持有 SK(双请求) |
---|---|---|
安全性 | 弱(私钥暴露风险) | 强(私钥仅服务端掌控) |
实现复杂度 | 客户端签名复杂 | 服务端接口管理复杂 |
性能开销 | 高(非对称算法开销大) | 可控(服务端可统一优化) |
适用场景 | 原生APP + 安全芯片 | Web 前端 / 普通客户端 |
访问控制 | 难实现,除非带 token | 签名接口可做强鉴权和权限控制 |
签名接口是否需要 | ❌ 不需要 | ✅ 需要 |
六、安全补充建议(通用)
安全点 | 建议 |
---|---|
签名内容 | 包含时间戳、nonce、path等防篡改参数 |
签名时效 | 签名有效期短(如5分钟内有效) |
签名接口控制 | 鉴权 + 频率限制 + IP限制 + 日志记录 |
SK 安全管理 | 数据库加密 + 动态轮换 + 单独授权 |
验签失败处理 | 记录日志 + 限流 + 告警 |
敏感接口保护 | 必须身份认证通过(token/session) + 验签 |
七、总结
签名不是万能的安全手段,而是 一环。你要把它放在:
✅ 签名 + 鉴权(身份)+ 权限控制 + 传输加密 + 风控追责
这 五层组合下看待,才能构建真正稳固的安全体系。
✅ 推荐方案选择
客户端环境 | 推荐签名方式 |
---|---|
原生 App、IoT、可信 SDK | 客户端持有私钥(非对称签名) |
浏览器、Web、小程序 | 服务端持有 SK(服务端签名) |
🔐 加密 vs 签名 —— 密钥使用对比笔记
一、基本概念对比
项目 | 签名(Signature) | 加密(Encryption) |
---|---|---|
目的 | 确认 数据来源合法性 和 完整性 | 保护 数据内容机密性 |
是否可逆 | ❌ 不可逆(摘要/散列值) | ✅ 可逆(密文可被解密) |
验证方式 | 发送方签名,接收方验签 | 发送方加密,接收方解密 |
是否隐藏内容 | 否,内容明文传输 | 是,内容密文传输 |
二、非对称加密算法下(如 RSA)的使用方式
场景 | 私钥(SK)作用 | 公钥(AK)作用 |
---|---|---|
签名 | 用私钥签名 | 用公钥验签 |
加密 | 用私钥解密 | 用公钥加密 |
三、所以加密场景下:谁持有 AK / SK?
这要看你想保护哪一端的数据隐私 —— 是保护服务端的数据?还是客户端?
✅ 情况 1:客户端加密 → 服务端解密(保护客户端数据)
-
客户端:持有 公钥(AK)
-
服务端:持有 私钥(SK)
✅ 流程
-
客户端用 公钥加密 数据
-
服务端用 私钥解密 数据
📌 应用场景
-
浏览器端传输银行卡、身份证等敏感信息
-
避免中间人嗅探请求数据内容
✅ 情况 2:服务端加密 → 客户端解密(保护服务端敏感响应)
-
服务端:持有 公钥(AK)
-
客户端:持有 私钥(SK)
✅ 流程
-
服务端用 客户端的公钥加密
-
客户端用 自己的私钥解密
📌 应用场景
-
服务端返回敏感信息(如凭证、密钥片段)
-
防止数据被中间人或其它客户端解密
四、对称加密下(如 AES)
-
AK/SK 是同一个密钥(只有一把密钥)
-
加密和解密双方都持有同一个密钥
项目 | 对称加密 |
---|---|
客户端密钥 | ✅ 有 |
服务端密钥 | ✅ 有(相同) |
传输风险 | 密钥一旦泄露全线失守 |
五、所以该谁持有什么密钥?
类型 | 客户端持有 | 服务端持有 | 风险说明 |
---|---|---|---|
非对称加密 | 公钥 | 私钥 | 安全 ✅(浏览器端只持公钥) |
签名验签 | 私钥 | 公钥 | ⚠️ 客户端私钥难保护 |
对称加密 | 同一个密钥 | 同一个密钥 | ⚠️ 密钥必须额外保护(可被抓包) |
六、总结:加密 vs 签名的 AK/SK 分工逻辑
目标 | 客户端持有 | 服务端持有 | 是否安全(建议) |
---|---|---|---|
签名(客户端签) | 私钥(SK) | 公钥(AK) | ❌(浏览器不安全) |
验签(服务端验) | ❌ | 公钥(AK) | ✅ |
加密(客户端加密) | 公钥(AK) | 私钥(SK) | ✅(推荐) |
解密(服务端解) | ❌ | 私钥(SK) | ✅ |
七、实际建议(前端浏览器环境)
操作 | 推荐实现方式 |
---|---|
数据保密传输 | 浏览器使用服务端公钥加密(非对称) |
数据完整性验证 | 服务端签名、前端验签(前端不能签) |
敏感参数传输 | 使用 HTTPS + 非对称加密混合模式 |
🔐 为什么需要两套密钥对?
用途 | 作用 | 所需密钥对 |
---|---|---|
① 客户端 ➡️ 服务端 | 传输参数:防止参数被窃听 | 服务端:私钥,客户端:公钥(用于加密) |
② 服务端 ➡️ 客户端 | 返回敏感数据:防止被中间人查看 | 客户端:私钥,服务端:公钥(用于加密) |
🔒 签名/验签 | 确保数据未被篡改 / 身份校验 | 签名方:私钥,验签方:公钥 |
🧠 对比来看,你可以这么理解:
✅ 加密的核心是:
-
谁持有私钥,谁就能解密,所以:
-
你要保护的数据 → 就必须谁来解密就让谁持有私钥
-
✅ 签名的核心是:
-
谁生成签名,谁就要持有私钥
-
谁验证签名,就需要知道公钥
🧩 举个完整的密钥配置例子:
功能场景 | 客户端持有 | 服务端持有 | 说明 |
---|---|---|---|
数据加密(上传参数) | 服务端公钥(用于加密) | 服务端私钥(用于解密) | 客户端 → 服务端的加密 |
数据加密(返回数据) | 客户端私钥(用于解密) | 客户端公钥(用于加密) | 服务端 → 客户端的加密 |
数据签名 | 客户端私钥(用于签名) | 客户端公钥(用于验签) | 客户端对上传内容签名 |
签名(反过来) | 服务端私钥(用于签名) | 服务端公钥(客户端验签) | 服务端对返回数据签名 |
🧱 所以你项目中密钥对可能是这样的:
名称 | 所有者 | 用途 |
---|---|---|
ClientKeyPair(客户端密钥对) | 客户端 | 服务端返回数据加密 + 客户端签名 |
ServerKeyPair(服务端密钥对) | 服务端 | 客户端上传数据加密 + 服务端签名 |
✅ 总结一句话:
传输保密 = 对方公钥加密,自己私钥解密
数据签名 = 自己私钥签名,对方公钥验签
所以,安全通信完整流程确实至少需要两套密钥对(甚至更多)。
🧱 一、项目中的密钥配置与用途总览表
密钥对名称 | 所属方 | 公钥用途 | 私钥用途 |
---|---|---|---|
ServerKeyPair | 服务端 | - 提供给客户端:客户端对敏感数据进行加密上传 - 客户端对服务端签名进行验签 | - 解密客户端加密的参数 - 对服务端返回的数据进行签名 |
ClientKeyPair | 客户端 | - 提供给服务端:服务端对敏感响应进行加密 - 服务端对客户端签名进行验签 | - 解密服务端加密的响应数据 - 对客户端上传的数据进行签名 |
🧭 二、完整通信流程图(双向加密 + 签名)
🧑💻 客户端 🖥️ 服务端
| |
|←—— Server 公钥 ——(通过配置或首次握手获取)———←|
| |
| |
🔐 加密上传参数 | |
|———[1] 用 Server 公钥加密参数 + Client 私钥签名 ——→|
| |
| 解密参数(Server 私钥)
| 验签(用 Client 公钥)
| |
| 处理业务逻辑并生成响应
| |
🔐 加密返回数据 | |
|←——[2] 用 Client 公钥加密响应 + Server 私钥签名 ——|
| |
解密响应(Client 私钥)
验签(用 Server 公钥)
🧠 注解说明:
-
加密方向使用对方公钥,确保只有接收方能解密。
-
签名方向使用自己私钥,确保发送方不可否认,接收方可验证。
-
服务端签名的目的是保护响应不可被中间人篡改。
-
客户端签名的目的是证明请求是“我本人”发的,未被篡改。
✅ 建议你如何实现:
🔧 密钥生成:
-
使用 RSA 2048 或更高位数密钥对。
-
密钥对应离线生成,公钥安全配置在通信对象处。
📦 传输规范建议(可以统一成一套 JSON 包):
{
"ak": "客户端标识",
"data": "Base64(RSA公钥加密内容)",
"signature": "Base64(RSA私钥签名)",
"timestamp": 1710000000000
}
🛡️ 安全补充建议:
-
签名数据中加入时间戳、nonce 以防重放攻击。
-
所有通信使用 HTTPS,防止中间人攻击。
-
服务端对客户端公钥做注册与绑定(防伪冒)。
✅ 总结一句话:
加密保护数据不被偷窥,签名保护数据不被篡改或伪造。
要实现真正安全的数据交互,至少两套密钥对是必要的基础设施。