3、数字签名概念:公私钥体系
聊到日志防篡改,数字签名是跑不掉的核心。你想想看,一条日志从产生到存储,中间经过好几个环节,怎么保证它没被人动过?数字签名就是干这个的。
我个人理解,数字签名其实就是现实世界里“亲笔签名”的电子版。只不过现实里签的是名字,电子世界里签的是——数学。
3.1 公私钥体系,说白了就是两把钥匙
公钥和私钥,是一对天生配对的数学钥匙。我给你打个比方:
- 私钥:你自己保管的,谁也不能给。它是签名用的。
- 公钥:公开出去的,谁都可以拿。它是验签用的。
我在项目中遇到过好几次,有人把私钥和公钥混着用,结果签名验签死活对不上。这里我强调一下:私钥签名,公钥验签,方向一定是固定的。
3.2 签名过程到底做了什么?
数字签名不是直接把内容加密。它有一套固定的流程。我习惯把它拆成三步:
- 哈希计算:对原始日志内容,跑一次哈希算法(比如SHA-256),得到一个固定长度的“摘要”。
- 私钥加密:用自己的私钥,对这个摘要进行加密。加密后的结果,就是签名。
- 附加输出:把原始日志 + 签名,一起存起来或发送出去。
你看,签名其实只加密了摘要,没加密原文。所以日志内容本身是明文的,任何人都能读。但签名是加密的,只有拿着对应公钥的人才能验。
// 伪代码示意:签名生成
digest = SHA256(log_content)
signature = RSA_private_encrypt(digest, private_key)
output = log_content + signature
3.3 验签过程,是签名的逆运算
验签就是反过来走一遍:
- 拆分:从收到的数据里,把原始日志和签名分开。
- 哈希原文:对原始日志,跑同样的哈希算法,得到摘要A。
- 公钥解密签名:用公钥解密签名,得到摘要B。
- 比对:如果摘要A == 摘要B,说明日志没被篡改,签名有效。
我曾经排查过一个线上问题,验签一直失败。查了半天,发现是验签时用了不同的哈希算法。嗯,这里要注意:签名时的哈希算法,必须和验签时完全一致。
// 伪代码示意:签名验证
digest_A = SHA256(received_log)
digest_B = RSA_public_decrypt(received_signature, public_key)
if (digest_A == digest_B) {
// 签名有效
} else {
// 数据被篡改或签名无效
}
3.4 公钥体系的两个核心特性
| 特性 | 说明 |
|---|---|
| 防抵赖性 | 私钥只有你一个人有,签名就是你发的,赖不掉。 |
| 完整性 | 日志内容一改,哈希值就变,验签必失败。 |
你想想看,这两个特性对日志存储多重要。日志一旦被改,马上能发现。谁改的,也能查到。
3.5 签名 ≠ 加密,别搞混了
很多人刚接触公私钥体系时,会把数字签名和数字加密搞混。我早期做项目时也踩过这个坑。
数字签名:私钥签名,公钥验签。目的是防篡改、防抵赖。内容本身可以是明文的。
数字加密:公钥加密,私钥解密。目的是保密。内容不能被别人看到。
我们做日志签名防篡改,用的是数字签名。日志内容不需要保密,但绝不能被人偷偷改掉。
3.6 实际项目中的密钥管理要点
私钥泄露 = 信任崩塌
私钥一旦泄露,别人就可以冒充你签名。所有已签名的日志,都可能被重新签名。我在项目中见过,因为私钥存成了明文文本文件,被开发同学git push上去了……那个项目后来全部重置。
建议做法
私钥放入硬件安全模块(HSM)或密钥管理服务(KMS)。代码里只引用密钥ID,不接触私钥原文。
3.7 签名算法的选型建议
算法不是越强越好,要看场景和性能。我个人常用的几种:
| 算法 | 签名长度 | 性能 | 推荐场景 |
|---|---|---|---|
| RSA-2048 | 256字节 | 适中 | 通用场景,兼容性好 |
| ECDSA P-256 | 64字节 | 较快 | 高并发、嵌入式场景 |
| Ed25519 | 64字节 | 很快 | 区块链、高性能需求 |
做日志签名,日志量大的话,我建议优先考虑ECDSA或Ed25519。签名短、计算快,存储和带宽压力都小。
3.8 本章知识结构图
下面的SVG图,画的是数字签名的核心流程:签名与验签。你一眼就能看明白公私钥的角色。
记住一句话
私钥签名是“你是谁”的证明,公钥验签是“你说了算不算”的检查。日志防篡改,全靠这套机制。