本文目录导读:

签名验证是一种用于确认数据完整性和身份真实性的技术,它确保数据在传输过程中没有被篡改,并且确实来自声称的发送方。
签名验证通常涉及非对称加密(公钥/私钥),但为了效率,它并不会直接加密整个数据,而是对数据的哈希值进行签名。
以下是签名验证的标准流程,以及常见的实现方式。
核心流程:签名与验签
签名阶段(发送方)
- 准备数据:发送方拥有需要发送的原始数据(
order_id=123&amount=100)。 - 计算哈希:使用哈希算法(如 SHA-256)对原始数据计算出一个摘要(Hash),这个摘要是固定长度的“指纹”。
- 私钥签名:发送方使用自己的私钥对哈希摘要进行加密,生成数字签名,这证明“数据是我(私钥持有者)签发的”。
- 发送:将 原始数据 和 数字签名 一起发送给接收方。
验签阶段(接收方)
- 接收数据:接收方收到原始数据和签名。
- 计算哈希:使用完全相同的哈希算法,对接收到的原始数据再次计算哈希摘要。
- 公钥解密:接收方使用发送方的公钥对签名进行解密,得到另一个哈希值。
- 比对结果:将步骤 2 自己算出的哈希值与步骤 3 解密出来的哈希值进行比对。
- 如果一致:验证通过,说明数据是发送方签发的(因为只有私钥能生成正确的签名),且数据未被篡改(因为数据变了,哈希值也会变)。
- 如果不一致:验证失败,可能是数据被篡改,或者签名是伪造的。
具体实现方式(代码示例 with Python)
以下使用 cryptography 库(比较现代和安全的库)演示最常见的 RSA 签名算法。
安装库
pip install cryptography
生成密钥对(发送方)
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
# 生成私钥 (Private Key)
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# 从私钥提取公钥 (Public Key)
public_key = private_key.public_key()
# 实际应用中,私钥要保存好,公钥发给接收方
签名(发送方)
message = b"order_id=123&amount=100&user=alice"
# 计算签名:使用私钥对消息进行哈希和签名
signature = private_key.sign(
message,
padding.PSS( # 推荐的安全填充方式
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256() # 哈希算法
)
print("签名:", signature.hex())
验签(接收方)
# 接收到:message 和 signature
try:
# 使用公钥进行验证
public_key.verify(
signature,
message,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("✅ 签名验证成功!数据完整,来源可信。")
except Exception as e:
print("❌ 签名验证失败:", e)
# 可能原因:数据被篡改、签名伪造、算法参数不匹配
常见的签名算法 vs 实际应用
| 算法 | 特点 | 推荐场景 |
|---|---|---|
| RSA | 历史悠久,广泛支持,速度较慢,密钥较长。 | Web API签名 (如支付宝/微信支付的老版本)、SSH、SSL。 |
| ECDSA | 基于椭圆曲线,密钥更短,性能更好,安全性高。 | 腾讯云API、区块链交易签名(如比特币、以太坊)、JWT。 |
| Ed25519 | 现代、速度快、抗侧信道攻击强、签名短。 | SSH新版密钥、现代密码学应用、高性能场景。 |
注意:不要再使用 MD5 或 SHA1 作为签名的哈希函数,它们已被证明不安全(可能碰撞)。
你实际开发中最常见的签名场景
API 接口签名(如微信支付、支付宝、AWS V4签名)
这是最常见的应用,通常是客户端用对称密钥或非对称私钥对请求参数排序后拼接的字符串进行签名,服务端校验。
关键步骤:
- 将所有参数(除签名本身)按字母序排序。
- 拼接成
key1=value1&key2=value2格式,加上密钥secretKey。 - 对拼接后的字符串用 MD5 / SHA-256 / HMAC-SHA256 生成签名。
- 服务端用相同方式计算签名并比对。
JWT (JSON Web Token)
JWT 的第三部分就是签名,JWT 使用 HMAC 对称算法 或 RSA/ECDSA 非对称算法 对 Header 和 Payload 进行签名。
- 对称算法 (HS256):只有一个秘钥,双方信任度高,适合服务端、客户端同属一个系统的场景。
- 非对称算法 (RS256/ES256):私钥签名,公钥验签,适合第三方服务验证身份。
文件完整性校验
下载文件时看到的 .sha256 文件本质上是文件的哈希值,加上签名后可以确保该下载链接不是被篡改过的恶意文件(如 apt-get / brew / 使用 gpg 签名)。
签名 vs MAC (消息认证码)
- 数字签名 (Signature):使用非对称加密(公钥/私钥)。公钥可以公开,接收方不需要知道私钥就能验签,具有不可否认性(Non-repudiation),因为只有私钥持有者才能签名。
- 消息认证码 (HMAC):使用对称加密(一个共享秘钥)。秘钥不能公开,发送方和接收方用同一个秘钥,不具备不可否认性(因为双方都能产生和验证签名)。
安全红线
- 保护私钥:私钥一旦泄露,签名系统完全崩塌。
- 防止重放攻击:签名本身不能防止对方重复发送同样的请求,需要在签名中加入时间戳 (
timestamp) 或随机数 (nonce)。 - 哈希选择:用 SHA-256 或更强算法,不要用 MD5 / SHA1。
- 填充模式:RSA 签名不要用
PKCS1v15(除非兼容旧系统),优先用PSS。 - 区分大小写:签名参数排序时,大小写规则要保持一致,避免验签失败。
- 原则:私钥签名,公钥验签。
- 做法:先哈希,再签名(或直接签名,但哈希更好);验签时,反向操作。
- 目的:确保数据没被改,且来源可靠。