本节摘要:数字签名用私钥对数据摘要签字、公钥验签,提供完整性与防抵赖;数字证书由证书颁发机构(CA)签名,把公钥和身份绑在一起;PKI(公钥基础设施)是签发、分发、吊销证书的整套体系。本节拆解签名的运作机理、证书链的校验过程、以及"信任 CA"的真实含义与代价。承接 4.3 节的三种密码学原语,本节完成凭据体系的装配,通往第 5 章的协议层。
4.3 节留下一个悬念:公钥可以随便发,但怎么确认收到的公钥真是对方的?设想中间人攻击(2.2 节)的升级版:攻击者守在信道中间,把你发出的真公钥换成自己的假公钥——此后"加密给对方"的每一段话,攻击者都能解。加密本身完好无损,败的是"公钥与身份的对应关系"。
这个问题的解法不是更强的数学,而是引入公证:找一个双方都信任的机构(CA),由它核验"这把公钥属于这个域名/这个人",并在核验后的文件上签字。这份被 CA 签过字、绑定了公钥与身份的文件,就是数字证书。信任问题从"你信这把公钥吗"转换为"你信这家 CA 吗"——从技术判断变成制度判断,这是密码学里少有的、由社会架构而非算法完成的飞跃。
签名不是"把字扫描进去",而是一套数学流程:发送方先对原文算哈希摘要,再用私钥加密这个摘要——签名值;接收方用公钥解出摘要,同时对原文重新算哈希,两者一致即验签通过。注意两个要点:签名签的是摘要而非原文(快,且原文可保持加密状态);私钥签名公钥验证,与加密方向(公钥加密私钥解密)正好相反——同一对密钥的两种用法。
签名同时兑现三样东西:完整性(原文改动一个字节,摘要对不上,验签失败)、真实性(只有私钥持有者能产出有效签名)、防抵赖(签名者事后无法否认——前提是私钥从未泄露)。三者合起来,就是"白纸黑字"的数字等价物。
一次真实的签名与验签会话:
$ openssl dgst -sha256 -sign 私钥.pem -out 更新包.sig 更新包.bin $ openssl dgst -sha256 -verify 公钥.pem -signature 更新包.sig 更新包.bin Verified OK # 接收端验签通过, 可信该包确系私钥持有者发布 # 篡改实验: 修改包内一个字节再验 $ printf 'x' | dd of=更新包.bin bs=1 seek=1024 conv=notrunc $ openssl dgst -sha256 -verify 公钥.pem -signature 更新包.sig 更新包.bin Verification Failure # 一个字节的改动即被捕获
一张证书的核心字段:域名/主体、公钥、有效期、签发者(CA)、以及 CA 对以上内容的数字签名。浏览器收到一个站点证书时的完整校验动作是沿证书链逐级验签:站点证书由中间 CA 签发,中间 CA 由根 CA 签发,而根 CA 的公钥预置在操作系统与浏览器的信任库里——链条的锚点叫信任锚。

PKI 除了签发还有两个运营动作常被忽视:吊销(私钥泄露后作废证书,经 CRL 或 OCSP 查询,实践中查询失败率不低,于是出现了 OCSP 装订等改进)与轮换(证书有有效期,续期要自动化——ACME 类协议把续期做成无人值守流程,就是被大量"忘续证书"事故逼出来的)。
内部服务同样需要证书纪律。 很多团队对外部站点证书管理严格,内部服务却用自签名证书加"关闭校验"跑通——等于给内网所有中间人攻击(2.2 节 ARP 欺骗)发了通行证。正确做法是内部自建 PKI 或用公开 ACME 流程,总之校验永远开着,信任缺失靠补证书解决,不靠关校验解决。
证书透明度与钉扎的取舍。 证书透明度日志让任何为你的域名签发的证书公开可查,误签发在几小时内可被发现;证书钉扎(App 内置指定公钥)更硬但运维风险大(换钥失误即自锁)。普通业务选前者加自动续期即可,钉扎留给高对抗场景。
⚠️ 常见坑:私钥进代码库。把 TLS 私钥或 API 签名密钥提交进版本库是最常见也最难挽回的事故之一——历史提交里它永远存在,全员都要当作已泄露处理:吊销、换钥、审计使用记录。
💡 关键直觉:把"信任 CA"翻译成工程语言就是"把身份判断外包给一家机构的运营纪律"。所以评估任何证书体系,真正要审计的不是加密强度,是 CA 的核验流程与你的证书运维自动化程度。
证书体系的故障形态高度套路化,应急手册可以写得很薄:
| 症状 | 根因 | 动作 |
|---|---|---|
| 部分用户证书报错,部分正常 | 证书链不完整(服务器没发中间证书) | 服务端补全链,勿让用户点"继续访问" |
| 全员报"证书过期" | 续期任务失败,无人盯 | 立即换发,随后接自动化续期 |
| 报"域名不匹配" | 证书里没有实际访问的域名 | 补域名重签,检查多域名场景 |
| 浏览器报"签发者异常" | 误入了自签名或私签证书 | 排查是否有中间人(2.2 节),核线路 |
| 换钥后部分服务报错 | 双钥并行期配置遗漏 | 按轮换预案补齐各服务配置 |
第一行值得展开:证书链不完整是最常见的"我这能打开你那打不开"事故——桌面端浏览器有缓存补偿,移动端与程序化客户端(App 内嵌页、支付回调)没有,于是故障只在部分渠道爆发,排查时极易走错方向。诊断口令是让 openssl 直接走一遍链校验,别只信自己浏览器能打开。
再补一条内网专属提醒:内部系统换证书时,调用方比人先受影响。浏览器用户还能看见报错点"继续",程序化调用方只会开始批量失败,而且失败形态千奇百怪(重试风暴、队列堆积、静默丢单)。内网换证书的标准动作因此是:提前发变更通告、列清全部调用方、切换后逐个确认——4.4 节正文说"校验永远开着",这份手册保证开着校验的系统不因换钥而翻车。
证书事故的源头常在开发环节,一张正反清单贴给所有写代码的人:
要做: 开发/测试/生产用三套独立证书与密钥 证书文件进密钥管理服务或秘密管理工具, 代码里只留引用 校验失败默认报错并留日志, 便于区分配置错与攻击 不要做: 把私钥提交进代码仓库 —— 提交历史里永远删不干净 在代码里关闭证书校验"先跑通再说" —— 这行注释是未来的事故工单 用生产证书跑测试环境 —— 泄露半径翻倍
清单里"关闭校验"一行值得再敲一次黑板:它通常以"临时""仅内网"的注释出现,而两个词在代码世界的含义都是"永久且全网"。代码评审看到证书校验被跳过,按 4.4 节正文的判词处理:要么补上正确证书,要么明确记录为待还的技术债并挂上期限——没有第三种处理。
本节收尾前,把整章的凭据体系串成一句话带走:认证确认"你是谁"(4.1),授权划定"你能动什么"(4.2),加密保证"说的话只有对方懂",哈希保证"内容没被动过",签名证明"这话确实是他说的",证书与 PKI 让这一切在陌生人之间也能成立(本节)。六句话对应六节,凭据体系的全部术语,说到底是这一句长话的六个从句。