TLS 连接中客户端验证证书的完整流程

张开发
2026/4/14 14:17:12 15 分钟阅读

分享文章

TLS 连接中客户端验证证书的完整流程
TLS 连接中客户端验证证书的完整流程一、先搞清楚几个前置概念在讲验证流程之前我们必须先理解几个核心概念否则后面的流程会看不懂。1. 什么是证书Certificate证书本质上就是一个电子文件里面记录了一些关键信息。你可以把它理解为一个身份证明文件。一张证书里主要包含以下内容持有者信息比如这个证书是颁发给www.example.com这个域名的。持有者的公钥服务器的公钥会被写在证书里面。颁发者信息谁签发了这张证书也就是哪个 CACertificate Authority证书颁发机构颁发的。有效期证书的起始时间和过期时间。签名算法颁发者用什么算法对这张证书进行签名的。数字签名颁发者对这张证书内容计算出来的签名值。2. 什么是数字签名数字签名是一种保证数据没有被篡改且确实是某人发出的技术手段。它的原理如下签名过程由 CA 完成第一步CA 拿到证书的原始内容持有者信息、公钥、有效期等对这些内容使用哈希算法如 SHA-256计算出一个固定长度的摘要值digest。第二步CA 用自己的私钥对这个摘要值进行加密加密后的结果就是数字签名。第三步把这个数字签名附在证书的末尾和证书内容一起发出去。验签过程由客户端完成第一步客户端拿到证书后用同样的哈希算法对证书内容计算出一个摘要值 A。第二步客户端用 CA 的公钥对证书末尾的数字签名进行解密得到摘要值 B。第三步比较 A 和 B如果相同说明证书内容没有被篡改并且确实是这个 CA 签发的。3. 什么是证书链Certificate Chain在现实中证书不是一张就完事了而是一条链。为什么呢世界上有很多 CA 机构但是根 CARoot CA的数量是有限的。根 CA 的证书叫做根证书是预先安装在你的操作系统或浏览器中的。这些根证书是绝对信任的锚点。但根 CA 不会直接给每个网站签发证书因为如果根 CA 的私钥泄露了所有证书都完了所以根 CA 的私钥使用得非常谨慎。实际操作中根 CA 会签发一个中间 CAIntermediate CA的证书然后由中间 CA 再去给具体的网站签发证书。这就形成了一条链根证书Root Certificate ← 预装在系统/浏览器中自签名 ↓ 签发 中间证书Intermediate Certificate ← 由根 CA 签发 ↓ 签发 服务器证书Server Certificate ← 由中间 CA 签发也叫叶子证书/终端实体证书服务器在 TLS 握手时通常会把服务器证书 中间证书一起发给客户端。根证书不需要发因为客户端本地已经有了。4. 什么是信任存储Trust Store每个操作系统和浏览器都内置了一个信任存储里面存放了所有被信任的根 CA 的证书。比如Windows 系统有自己的证书存储macOS 有 KeychainLinux 通常在/etc/ssl/certs/目录Firefox 浏览器有自己独立的信任存储使用 NSS 库Java 有cacerts文件当客户端需要验证一个证书时最终必须追溯到这个信任存储中的某一个根证书验证才算通过。二、TLS 握手的大背景在讲客户端验证证书之前我们先快速了解这个验证发生在 TLS 握手的哪个阶段。以 TLS 1.2 为例客户端 服务器 | | |-------- ClientHello ------------------ | (1) 客户端发起连接 | | |------- ServerHello -------------------| | (2) 服务器回应 |------- Certificate -------------------| | (3) 服务器发送证书 ★ |------- ServerKeyExchange -------------| | (4) 密钥交换参数 |------- ServerHelloDone ---------------| | (5) 服务器招呼完毕 | | | 【客户端在此处验证证书】 ★ | | | |-------- ClientKeyExchange ------------- | (6) 客户端密钥交换 |-------- ChangeCipherSpec -------------- | (7) 切换加密 |-------- Finished ---------------------- | (8) 完成 | | |------- ChangeCipherSpec --------------| | (9) 服务器切换加密 |------- Finished ----------------------| | (10) 完成 | | | 加密通信开始 |关键时机客户端收到服务器发来的Certificate消息后在发送ClientKeyExchange之前会对服务器的证书进行完整验证。如果验证失败客户端会直接终止连接发出一个alert消息。三、客户端验证证书的详细流程下面进入核心内容。客户端拿到服务器发来的证书通常是一条证书链后会依次进行以下几个步骤的验证。每一步都必须通过只要有一步失败整个验证就失败。第一步构建证书链客户端首先要做的是构建一条完整的证书链从服务器证书叶子证书一直追溯到一个被信任的根证书。具体过程客户端拿到服务器发来的证书列表。通常服务器会按顺序发送第一张是自己的服务器证书后面依次是中间证书。客户端从服务器证书开始检查这张证书的颁发者Issuer字段然后在收到的证书列表中找到颁发者对应的那张中间证书。再检查这张中间证书的颁发者字段继续往上找直到找到一张证书它的颁发者就在客户端本地的信任存储中即根证书。如果最终无法追溯到一个受信任的根证书验证失败。浏览器会报错比如常见的ERR_CERT_AUTHORITY_INVALID。注意事项有时候服务器配置不当没有发送中间证书客户端可能会尝试通过证书中的 AIAAuthority Information Access扩展字段提供的 URL 去下载缺失的中间证书。但这不是所有客户端都支持的行为有的客户端比如某些 Android 版本直接就会报错。有些证书链可能有多条路径交叉签名的情况客户端需要尝试找到至少一条有效路径。第二步验证每一级证书的数字签名证书链构建好之后客户端需要从上往下也可以说从根证书往叶子证书的方向逐级验证每张证书的数字签名。具体过程验证中间证书的签名拿根证书中的公钥去验证中间证书上的数字签名。用根证书的公钥解密中间证书的签名得到摘要值 B。对中间证书的内容用相同的哈希算法计算摘要值 A。比较 A 和 B一致则说明这张中间证书确实是根 CA 签发的且内容没有被篡改。验证服务器证书的签名拿中间证书中的公钥去验证服务器证书上的数字签名。过程同上。如果链条更长有多级中间 CA就逐级往下验证每一级都用上一级的公钥来验证下一级的签名。如果签名验证失败说明什么证书可能被篡改了中间人攻击。证书可能是伪造的。证书链可能搭配错误。第三步检查证书的有效期每张证书都有Not Before生效时间和Not After过期时间两个字段。具体过程客户端获取当前系统时间。检查证书链中每一张证书包括中间证书的有效期。如果当前时间早于Not Before证书还没有生效验证失败。如果当前时间晚于Not After证书已经过期验证失败。常见场景用户电脑的系统时间不对比如时钟回退到了 2010 年会导致大量网站证书验证失败。这就是为什么有时候修改系统时间后浏览器会报证书错误。网站管理员忘记续期证书证书过期了用户访问时就会看到证书过期的警告。第四步验证域名匹配主机名验证这一步非常关键。即使证书的签名验证通过了、没有过期客户端还需要检查这张证书是不是颁发给当前正在访问的域名的。为什么需要这一步假设攻击者拿到了一张合法的证书比如evil.com的证书然后在你访问bank.com时把自己的证书发给你。如果不检查域名匹配你的客户端会认为这张证书是合法的但它其实不是bank.com的证书。具体过程客户端检查服务器证书中的SANSubject Alternative Name扩展字段。SAN 字段中列出了这张证书适用的所有域名比如DNS: www.example.com DNS: example.com DNS: *.example.com客户端将当前访问的域名比如www.example.com与 SAN 中列出的域名逐一比较。如果 SAN 中没有匹配的再检查证书的Subject 字段中的 CNCommon Name。但这种方式已经被逐渐废弃现代浏览器如 Chrome已经不再使用 CN 来做域名匹配只看 SAN。支持通配符匹配*.example.com可以匹配www.example.com、mail.example.com但不能匹配example.com本身也不能匹配sub.www.example.com通配符只能匹配一级。如果没有任何域名匹配验证失败。浏览器会报ERR_CERT_COMMON_NAME_INVALID。第五步检查证书吊销状态有时候一张证书在有效期内但由于私钥泄露或其他安全原因CA 需要提前作废这张证书。这个过程叫做证书吊销Revocation。客户端需要检查证书是否已经被吊销。客户端有两种主要方式来检查吊销状态方式一CRLCertificate Revocation List证书吊销列表CA 会定期发布一份吊销列表列出所有被吊销的证书的序列号。证书中有一个扩展字段叫CRL Distribution Points里面包含了一个 URL客户端可以去这个 URL 下载 CRL 文件。客户端下载 CRL 后检查当前证书的序列号是否在列表中。缺点CRL 文件可能很大包含成千上万条记录下载慢而且 CRL 的更新有延迟可能存在窗口期内被吊销的证书仍然被认为有效。方式二OCSPOnline Certificate Status Protocol在线证书状态协议这是一种实时查询的方式。客户端向 CA 的 OCSP 服务器发送请求查询某张特定证书的状态。证书中有一个扩展字段叫Authority Information Access (AIA)里面包含 OCSP 服务器的 URL。OCSP 服务器会回应三种状态之一good有效、revoked已吊销、unknown未知。优点比 CRL 高效因为只查询一张证书的状态不需要下载整个列表。缺点需要额外的网络请求可能增加延迟如果 OCSP 服务器宕机怎么办OCSP StaplingOCSP 装订为了解决 OCSP 的延迟和隐私问题因为客户端直接向 CA 查询暴露了用户在访问哪个网站出现了 OCSP Stapling 技术服务器自己定期去 CA 的 OCSP 服务器查询自己的证书状态得到一个带有 CA 签名的 OCSP 响应。在 TLS 握手时服务器把这个 OCSP 响应装订在证书旁边一起发给客户端。客户端验证这个 OCSP 响应的签名确认是 CA 签发的然后检查证书状态。这样客户端就不需要自己再去联系 OCSP 服务器了。实际情况很多浏览器对吊销检查的策略是软失败soft-fail如果无法获取 CRL 或 OCSP 响应比如网络不通就假设证书没有被吊销继续通过验证。这是因为如果采用硬失败策略CRL/OCSP 服务器一旦宕机所有 HTTPS 网站都将无法访问。Chrome 浏览器曾经放弃了传统的 CRL/OCSP 检查改用自己维护的CRLSets一种精简版的吊销列表通过浏览器更新推送。第六步检查证书的扩展字段和约束除了上面几个核心步骤客户端还会检查证书中的一些扩展字段6.1 基本约束Basic Constraints检查证书是否是 CA 证书可以签发其他证书还是终端实体证书。根证书和中间证书的CA字段必须为TRUE。服务器证书叶子证书的CA字段必须为FALSE或者不包含此扩展。如果一张普通的服务器证书声称自己是 CA客户端应该拒绝。6.2 密钥用途Key Usage证书中会标明这个公钥可以用于什么用途比如Digital Signature数字签名、Key Encipherment密钥加密等。CA 证书的 Key Usage 中必须包含Certificate Sign证书签名否则它没有资格签发证书。服务器证书的 Key Usage 需要与 TLS 握手中使用的密钥交换算法匹配。6.3 增强型密钥用途Extended Key Usage, EKU更细粒度的用途限制。比如服务器证书应该包含Server Authentication服务器认证这个 EKU 值。如果一张证书的 EKU 只标明了Code Signing代码签名那它不能用于 TLS 服务器认证。6.4 名称约束Name Constraints某些中间 CA 证书可能有名称约束限制它只能签发特定域名范围内的证书。比如一个企业内部 CA 可能只允许签发*.company.com范围内的证书。客户端在验证链条时需要检查每一级 CA 的名称约束确保下级证书的域名在允许范围内。6.5 路径长度约束Path Length Constraint在 Basic Constraints 中CA 证书可以设置一个路径长度约束限制这个 CA 下面最多还能有几级中间 CA。比如路径长度约束为 0表示这个 CA 只能直接签发终端实体证书不能再签发中间 CA 证书。第七步检查签名算法的强度客户端还会检查证书使用的签名算法是否足够安全。如果证书使用了已知不安全的算法比如 MD5 或 SHA-1现代浏览器会拒绝该证书或给出警告。目前主流要求至少使用 SHA-256 作为哈希算法。RSA 密钥长度至少 2048 位。四、验证流程的总结完整流程图把上面所有步骤串起来客户端验证证书的完整流程如下收到服务器证书 │ ▼ ① 构建证书链 从叶子证书追溯到根证书 │ ├── 失败 → 终止连接证书颁发机构不受信任 │ ▼ ② 逐级验证数字签名 用上级的公钥验证下级的签名 │ ├── 失败 → 终止连接证书签名无效 │ ▼ ③ 检查有效期 每张证书的 Not Before / Not After │ ├── 失败 → 终止连接证书已过期或证书尚未生效 │ ▼ ④ 验证域名匹配 SAN 字段与请求域名比对 │ ├── 失败 → 终止连接证书与域名不匹配 │ ▼ ⑤ 检查吊销状态 CRL / OCSP / OCSP Stapling │ ├── 已吊销 → 终止连接证书已被吊销 ├── 无法查询 → 大多数浏览器软失败继续 │ ▼ ⑥ 检查扩展字段和约束 Basic Constraints / Key Usage / EKU / Name Constraints 等 │ ├── 失败 → 终止连接 │ ▼ ⑦ 检查签名算法强度 拒绝 MD5 / SHA-1 等弱算法 │ ├── 失败 → 终止连接或警告 │ ▼ ✅ 证书验证通过继续 TLS 握手五、为什么这套机制能防止中间人攻击理解了上面的流程后我们来想想如果有个攻击者试图在你和服务器之间做中间人攻击他有哪些可能的手段以及为什么都会失败场景 1攻击者伪造一张假证书攻击者无法伪造 CA 的签名因为他没有 CA 的私钥。客户端在第二步验证签名时就会发现不对。场景 2攻击者用自己的合法证书比如 evil.com来冒充 bank.com客户端在第四步域名匹配时会发现证书是 evil.com 的不是 bank.com 的验证失败。场景 3攻击者截获了一张真实的 bank.com 证书原样转发给客户端证书是真的验证能通过。但是攻击者没有 bank.com 的私钥。在后续的密钥交换阶段比如 ECDHE攻击者无法完成密钥交换因为他不拥有证书中公钥对应的私钥。所以光有证书没用还需要有私钥才能完成 TLS 握手。场景 4攻击者搞到了一张已经泄露私钥的证书CA 会吊销这张证书。客户端在第五步检查吊销状态时会发现证书已被吊销。六、TLS 1.3 中的变化在 TLS 1.3 中握手流程有所精简但证书验证的逻辑基本不变。主要区别是TLS 1.3 的握手更快1-RTT 甚至 0-RTT证书在握手的更早阶段就被加密传输了ServerHello 之后的数据都是加密的第三方窃听者无法看到证书内容。服务器在发送证书后还会发送一个CertificateVerify消息用自己的私钥对之前的握手消息进行签名证明自己确实拥有证书中的公钥对应的私钥。客户端会验证这个签名。废弃了 RSA 密钥交换方式只保留 (EC)DHE提供前向安全性。七、高频面试题及回答话术面试题 1TLS 握手中客户端是如何验证服务器证书的回答话术客户端收到服务器发来的证书后主要做以下几个方面的验证第一构建并验证证书链。客户端从服务器证书开始通过每张证书的颁发者信息逐级向上追溯直到找到一个本地信任存储中的根证书。如果找不到可信的根则验证失败。第二逐级验证数字签名。用上一级证书的公钥去验证下一级证书的签名确保每一级证书确实是由其声称的颁发者签发的且内容没有被篡改。第三检查有效期。确保链中每张证书都在有效期内。第四域名匹配。检查服务器证书的 SANSubject Alternative Name字段中的域名是否与当前访问的域名一致。第五检查吊销状态。通过 CRL 或 OCSP或 OCSP Stapling检查证书是否被 CA 提前吊销了。第六还会检查一些扩展字段比如 Basic Constraints、Key Usage、签名算法强度等。所有步骤都通过后证书验证才算成功然后继续 TLS 握手的后续步骤。面试题 2什么是证书链为什么需要证书链回答话术证书链是从服务器证书到根证书之间的一条信任路径。通常包含三层根证书、中间证书和服务器证书。之所以需要证书链是因为根 CA 的私钥极为重要如果直接用来签发大量终端证书一旦泄露影响面太大。所以根 CA 通常会签发中间 CA 的证书再由中间 CA 去签发服务器证书。这样即使某个中间 CA 出了问题只需要吊销这个中间 CA 的证书不影响根 CA 和其他中间 CA 签发的证书。客户端验证时就是沿着这条链条逐级验证签名最终追溯到本地预装的根证书来确认整条链的可信性。面试题 3OCSP 和 CRL 的区别是什么OCSP Stapling 又是什么回答话术CRL 是证书吊销列表CA 定期发布一份包含所有被吊销证书序列号的文件客户端需要下载整个列表来查询。缺点是列表可能很大更新有延迟。OCSP 是在线证书状态协议客户端针对某张特定证书向 CA 的 OCSP 服务器发起实时查询服务器返回这张证书是有效、吊销还是未知。优点是更高效不需要下载整个列表缺点是增加了一次网络请求的延迟而且会暴露用户的访问记录给 CA。OCSP Stapling 是对 OCSP 的优化。由服务器定期向 CA 查询自己证书的 OCSP 响应然后在 TLS 握手时把这个响应装订在证书旁边发给客户端。客户端直接验证这个 OCSP 响应的签名即可不需要自己再去联系 CA。这样既解决了延迟问题也保护了用户隐私。面试题 4如果证书验证失败客户端会怎么做回答话术如果证书验证失败客户端会发送一个 TLS Alert 消息给服务器终止握手过程。具体的 Alert 类型取决于失败原因比如bad_certificate证书损坏、certificate_expired证书过期、unknown_ca未知的 CA、certificate_revoked证书被吊销等。在浏览器中用户会看到证书错误页面。不同浏览器有不同的处理方式对于某些非致命的错误比如过期用户可以选择继续访问但对于使用了 HSTSHTTP Strict Transport Security的网站浏览器不允许用户跳过警告必须终止连接。面试题 5为什么攻击者不能直接截获真实证书来进行中间人攻击回答话术证书是公开的攻击者确实可以获取到服务器的真实证书。但光有证书没用因为攻击者没有证书中公钥所对应的私钥。在 TLS 握手的密钥交换阶段服务器需要用自己的私钥来完成某些操作。比如在 TLS 1.3 中服务器需要发送 CertificateVerify 消息用私钥对握手消息签名来证明自己确实拥有该证书。如果攻击者没有私钥就无法生成正确的签名客户端会发现验证不通过。所以 TLS 的安全性依赖两个东西证书证明身份私钥证明拥有权。缺一不可。面试题 6自签名证书为什么浏览器会报不安全回答话术自签名证书是指由自己生成的、不经过任何受信任 CA 签发的证书。它的颁发者就是自己签名也是用自己的私钥做的。浏览器报不安全的原因在于客户端在构建证书链时无法追溯到本地信任存储中的任何一个受信任的根证书。自签名证书没有经过权威 CA 的背书客户端无法确认持有这张证书的人的身份是否可信。从技术上说自签名证书的签名验证本身是可以通过的用证书自己的公钥验证自己的签名但因为这个根不在信任存储中所以整条信任链是断裂的。除非用户手动将这张自签名证书添加到信任存储中。

更多文章