TLS、PKI 与 HTTPS
内容摘要:传输层安全协议(Transport Layer Security,TLS)在不可信网络上为应用数据提供机密性、完整性和对端身份认证。HTTPS 是 HTTP over TLS。本章从 TLS 1.3 握手、密钥派生和记录层出发,解释公钥基础设施(Public Key Infrastructure,PKI)的证书路径、DNS 服务身份校验、吊销机制、SNI/ALPN、会话恢复、0-RTT 与双向 TLS,并用
openssl、curl和本地证书实验建立证据驱动的排障方法。难度:高级 | 前置知识:13 TCP 连接、15 DNS、16 HTTP | 所属层次:应用层安全协议,位于 HTTP 与 TCP/QUIC 之间
一、TLS 的安全目标与边界
TLS 的核心目标是:
| 目标 | TLS 如何实现 | 不代表什么 |
|---|---|---|
| 机密性 | 用协商出的对称密钥加密记录 | 不隐藏 IP、端口、流量长度和时序等全部元数据 |
| 完整性 | 认证加密检测记录篡改 | 不阻止端点自身篡改、记录或泄露明文 |
| 服务端认证 | 证书路径、名称、时间等校验 | 有效证书不等于网站内容可信、业务无漏洞 |
| 可选客户端认证 | 客户端证书与私钥持有证明 | 不自动完成应用授权与租户隔离 |
TLS 不能自动防止:
- 终端或服务器已经被入侵。
- XSS、SQL 注入、SSRF、越权、恶意业务响应。
- 密钥、Cookie、Authorization 或明文在端点日志中泄露。
- 客户端信任了恶意根 CA,或跳过证书校验。
- 流量分析和可用性攻击。
二、密码学组件如何分工
现代 TLS 不是“直接用证书公钥加密所有 HTTP 数据”,而是组合多种密码学组件:
| 组件 | 典型算法/机制 | 作用 |
|---|---|---|
| 密钥协商 | ECDHE | 双方产生共享秘密;使用临时密钥时提供前向保密 |
| 身份签名 | ECDSA、RSA-PSS | 服务端用证书对应私钥证明身份并绑定握手 transcript |
| 密钥派生 | HKDF | 从共享秘密和握手上下文派生不同方向、不同阶段的密钥 |
| 认证加密 | AES-GCM、ChaCha20-Poly1305 | 同时提供应用记录的机密性与完整性 |
| 哈希 | SHA-256、SHA-384 | transcript、HKDF 和签名相关计算 |
| 随机数/序列 | CSPRNG、record sequence | 防止密钥或 nonce 重用 |
ECDHE(Elliptic Curve Diffie-Hellman Ephemeral,椭圆曲线临时 Diffie-Hellman)双方交换的是公有参数,不发送最终共享秘密:
前向保密的边界
使用临时 (EC)DHE 时,未来泄露证书长期私钥通常不能解密过去已捕获的完整握手流量。但仍有边界:
- 端点内存、会话票据密钥或流量密钥泄露仍可能暴露对应连接。
- TLS 1.3 的 0-RTT early data 由恢复 PSK 派生,安全属性弱于普通 1-RTT 应用数据。
- 若实现复用临时私钥、随机数失效或算法实现有漏洞,标准设计无法弥补。
三、TLS 1.3 完整握手
TLS 1.3 由 RFC 8446 定义。典型基于证书的完整握手在网络可达且无额外重试时需要 1 个 TLS RTT;它发生在 TCP 三次握手之后。HTTP/3 则把 TLS 1.3 集成在 QUIC 握手中,不存在独立 TCP 阶段。
花括号表示该消息在 ServerHello 之后通常已经受握手流量密钥保护。
1、关键消息
| 消息 | 发送方 | 关键内容 | 失败线索 |
|---|---|---|---|
| ClientHello | 客户端 | 随机数、支持版本、cipher suites、key shares、SNI、ALPN、签名算法 | 太大、扩展不兼容、无共同参数 |
| ServerHello | 服务端 | 选定版本、cipher suite、key share | protocol_version、handshake_failure |
| EncryptedExtensions | 服务端 | 不参与证书的协商结果,如 ALPN | ALPN 不匹配 |
| Certificate | 服务端 | 叶证书与通常所需的中间证书 | 缺链、过期、用途不符 |
| CertificateVerify | 服务端 | 用叶证书私钥签名握手 transcript | 私钥不匹配、签名算法不支持 |
| Finished | 双方 | 对握手 transcript 的密钥确认 | 握手被篡改、密钥推导不一致 |
2、HelloRetryRequest
若客户端提供的 key_share 不适合服务端,服务端可用 HelloRetryRequest 要求另一组参数。这会增加往返时间。抓包中看到第二个 ClientHello 不应立即判断为重传;要检查服务端返回的是重试请求还是网络层重复。
四、TLS 1.2 与 TLS 1.3 对比
| 维度 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| 主要规范 | RFC 5246 | RFC 8446 |
| 完整握手常见往返 | 通常 2 个 TLS RTT | 通常 1 个 TLS RTT |
| cipher suite 含义 | 同时编码密钥交换、认证、加密与哈希组合 | 只选择 AEAD 与 HKDF 哈希,密钥交换/签名独立协商 |
| 静态 RSA 密钥交换 | 标准曾允许,现代安全配置不应使用 | 已移除 |
| 对称算法 | 兼容 CBC 与 AEAD,安全配置应选 AEAD | 只保留 AEAD |
| 握手加密 | 大部分握手消息明文 | ServerHello 后多数握手消息加密 |
| 恢复 | Session ID / Session Ticket | 基于 PSK,通常由 NewSessionTicket 建立 |
| 0-RTT | 无标准化 TLS early data | 支持,但存在重放风险 |
1、TLS 1.2 静态 RSA 握手(历史兼容机制)
静态 RSA 密钥交换的典型 TLS 1.2 流程如下。这里的 RSA 同时承担服务器认证和密钥传输,不能与 ECDHE_RSA 混为一谈:
它的关键限制:
- 服务器长期 RSA 私钥一旦在未来泄露,历史抓包中的
ClientKeyExchange可能被解密,不提供前向保密。 - RSA PKCS#1 v1.5 解密错误处理曾引出 Bleichenbacher 类填充预言机风险,实现必须做复杂防护。
- TLS 1.3 已移除静态 RSA 密钥交换。
- 现代 TLS 1.2 配置也应优先 ECDHE。
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 中:
ECDHE负责临时密钥协商并提供前向保密;RSA表示服务器通常用 RSA 证书私钥签名握手参数来证明身份;- 它不是“客户端用 RSA 公钥加密 premaster secret”的静态 RSA 流程。
示例 cipher suite:
TLS 1.2: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS 1.3: TLS_AES_128_GCM_SHA256TLS 1.3 名称没有写 ECDHE 或 RSA,不代表没有密钥交换和证书签名;这些由 supported_groups、key_share、signature_algorithms 和认证消息单独协商。
部署原则:RFC 9325(BCP 195)是通用安全建议,但具体最低版本还受客户端兼容性、监管要求和产品支持周期约束。新系统优先 TLS 1.3,并保留经过加固的 TLS 1.2 作为有明确兼容需求时的下限;不要重新启用 SSLv2、SSLv3、TLS 1.0/1.1 或弱密码套件来“临时修复”握手。
2、TCP 与 TLS 能否“同时握手”
常规 TCP socket 的逻辑顺序仍是:TCP 建连成功后,TLS 才能在该可靠字节流上传输 ClientHello。但“逻辑依赖”不等于抓包中一定严格分成互不重叠的多个往返:
- TCP 第三次握手的 ACK 可以携带数据,客户端实现可能把
ClientHello与该 ACK 一起发送。 - TCP Fast Open(TFO)允许在满足 cookie 等条件时于 SYN 携带数据,可进一步重叠 TCP 和上层握手;中间设备兼容性与重放语义必须评估。
- TLS 1.3 会话恢复可使用 0-RTT early data,但 early data 可被重放,只适合明确允许重放的操作。
- QUIC 把传输与 TLS 1.3 握手集成,不存在独立 TCP 三次握手。
因此优化目标应按实际连接复用率、RTT、恢复命中率和协议协商结果测量,不能简单宣称“TCP 与 TLS 永远需要固定 3 个 RTT”或“已经完全同时完成”。
五、TLS 记录层
TLS 把上层字节切分为记录(record),加密后交给 TCP;接收方认证、解密、重组后交给应用。TLS 记录边界不等于 HTTP 消息边界,也不等于 TCP segment 边界。
TLS 1.3 TLSCiphertext 外层字段:
| 字段 | 长度 | 典型值/含义 | 抓包观察 |
|---|---|---|---|
opaque_type | 1 字节 | 加密记录通常显示 application_data(23) | Wireshark tls.record.content_type |
legacy_record_version | 2 字节 | 固定兼容值 0x0303 | 不能据此断言协商成 TLS 1.2 |
length | 2 字节 | 后续加密记录长度 | 可泄露长度模式 |
encrypted_record | 变长 | 加密内容、内层类型、可选 padding、AEAD tag | 无密钥时不可见明文 |
关键性质:
- 每个方向使用独立流量密钥。
- AEAD nonce 与记录序号相关;实现必须避免同一密钥下 nonce 重用。
- TLS 1.3 把真实内层内容类型放进密文,外部观察者通常只见
application_data。 - 连接长期运行时可用
KeyUpdate更新应用流量密钥,但支持和触发策略属于实现差异。
六、PKI 与证书链
X.509 证书把一个公钥与主体名称、有效期、用途等信息绑定,并由签发者签名。TLS 服务端通常发送:
- 叶证书:代表目标服务,持有对应私钥。
- 中间 CA:由上级 CA 授权签发下级证书,服务端通常必须发送。
- 根 CA / Trust Anchor:由客户端信任库预先配置,通常不需要由服务端发送。
- 交叉签名:可能存在多条可构建路径,客户端选路能力和信任库会影响结果。
1、证书关键字段
| 字段/扩展 | 作用 | 校验要点 |
|---|---|---|
| Subject | 证书主体描述 | 不能用 Common Name 代替现代 DNS 身份匹配 |
| Issuer | 签发者描述 | 只是路径线索,最终还要验证签名与约束 |
| Serial Number | 签发者范围内唯一标识 | 吊销查询常用 |
| Validity | notBefore / notAfter | 客户端时间必须处于有效区间 |
| Subject Public Key Info | 主体公钥与算法 | 强度、算法和私钥匹配 |
| SAN | DNS、IP 等服务身份 | DNS 用 dNSName,IP 字面量用 iPAddress |
| Basic Constraints | 是否 CA、path length | 中间 CA 应为 CA:TRUE |
| Key Usage | 签名、证书签发等底层用途 | CA 与叶证书用途不能混淆 |
| Extended Key Usage | serverAuth、clientAuth 等 | 服务端证书需允许目标用途 |
| Authority Key Identifier | 帮助定位签发者密钥 | 不能替代签名校验 |
| CRL Distribution Points / AIA | CRL、OCSP、Issuer 获取位置 | 网络获取行为因客户端而异 |
PEM 是 Base64 与头尾标记组成的文本封装;DER 是 ASN.1 的二进制编码。二者可以承载同一证书内容,不代表不同信任级别。
七、证书路径与服务身份校验
“证书验证成功”不是一个单独的签名检查,而是一组独立条件:
1、主机名校验
RFC 9525 定义 TLS 应用服务身份校验的现代规则。对 DNS 名称:
- 客户端先确定自己要访问的参考身份,例如 URL 中的
www.example.com。 - 在证书 SAN 扩展的
dNSName中查找匹配项。 - 不把 Subject Common Name(CN)作为回退身份。
- 通配符只匹配受限的最左侧标签;
*.example.com不匹配a.b.example.com,也不匹配裸example.com。 - 直接访问 IP 字面量时,应匹配 SAN 的
iPAddress,不能把 DNS SAN 当成 IP 身份。
SNI(Server Name Indication,服务器名称指示)和证书名称校验是两件事:
SNI:客户端告诉服务器“请给我哪个虚拟主机的配置/证书”
SAN 校验:客户端确认服务器给出的证书是否代表自己原本要访问的身份发送正确 SNI 不会自动完成身份校验;证书 SAN 正确也不能修复连接发往错误 IP 的路由或 DNS 问题。
2、时间校验
证书在 notBefore 前尚未生效,在 notAfter 后已经过期。生产排障要同时确认:
- 客户端、服务端和证书管理系统时钟。
- 时区显示与 UTC 原始时间。
- 证书是否已轮换但代理/节点仍加载旧文件。
- 多副本是否返回不同证书。
调整系统时间会影响日志、分布式系统和其他证书,不能把“改时间”当常规修复手段。
八、SNI 与 ALPN
1、SNI
一台 IP:port 可承载多个 HTTPS 虚拟主机。客户端在 ClientHello.server_name 发送 DNS 名称,服务器据此选择证书和配置。
经典 TLS ClientHello 中 SNI 通常可被路径观察者看到;即使后续 HTTP 被加密,也不能假设访问域名完全隐藏。Encrypted ClientHello(ECH)的部署会改变这一点,但客户端、DNS 记录、服务端和中间网络必须共同支持,不能默认所有环境已启用。
2、ALPN
应用层协议协商(Application-Layer Protocol Negotiation,ALPN)在 TLS 握手中选择上层协议:
| ALPN ID | 常见含义 | 传输 |
|---|---|---|
http/1.1 | HTTP/1.1 | TLS over TCP |
h2 | HTTP/2 | TLS over TCP |
h3 | HTTP/3 | TLS integrated with QUIC/UDP |
客户端不能在服务端选择 h2 后发送 HTTP/1.1 文本。没有共同 ALPN 时,结果取决于应用协议和实现:可能回退到约定默认值,也可能握手或应用层失败。
九、会话恢复、PSK 与 0-RTT
TLS 1.3 服务端可在连接建立后发送 NewSessionTicket。客户端以后把票据关联的预共享密钥(Pre-Shared Key,PSK)用于恢复:
恢复的收益:
- 减少证书签名等公钥操作。
- 在适当条件下降低 CPU 和握手时延。
- 可选择允许 0-RTT early data。
票据不是“永久登录凭证”:
- 服务端需轮换并保护 ticket encryption keys。
- 多节点要设计共享/分区策略,否则命中率低或扩大密钥泄露范围。
- 票据有生命周期,并绑定协议参数与服务策略。
- 客户端必须能在恢复被拒绝时完成完整握手。
1、0-RTT 的重放风险
客户端可在首个恢复 ClientHello 后立即发送 early data,但网络攻击者可能重放这些数据。TLS 不能替应用判断一次业务操作是否可重复。
只应允许可重放、幂等且无副作用的操作,并同时实施:
- 服务端 anti-replay 策略与短票据窗口。
- 应用 Idempotency-Key、nonce 或唯一业务约束。
- 禁止支付、下单、权限变更、消息发送等非幂等操作进入 0-RTT。
- 正确处理服务端拒绝 early data 后的重发,避免应用重复执行。
十、双向 TLS
双向 TLS(Mutual TLS,mTLS)在服务端证书认证之外,要求客户端也提交证书并证明持有私钥:
mTLS 适合服务到服务、设备身份和高保证内部接口,但必须单独解决:
- 证书签发、轮换、撤销和私钥保护。
- 证书身份到应用账号、角色、租户的授权映射。
- 代理终止 TLS 后如何可信地向上游传递已验证身份。
- 客户端时钟、证书过期与 CA 迁移。
- 信任域过宽导致任一受信客户端越权。
十一、吊销:CRL、OCSP 与 Stapling
证书在到期前因私钥泄露、误签或主体变化而失效时,需要吊销机制。
| 机制 | 工作方式 | 优点 | 限制 |
|---|---|---|---|
| CRL | 下载证书吊销列表 | 可离线缓存、模型简单 | 列表可能大,更新存在窗口 |
| OCSP | 客户端向响应器查询序列号状态 | 单证书查询、状态较新 | 增加网络依赖并泄露访问隐私 |
| OCSP Stapling | 服务端把 CA 签名的 OCSP 响应附在握手中 | 降低客户端延迟与隐私泄露 | 服务端必须及时刷新;客户端策略不一 |
| 短生命周期证书 | 缩短有效期并自动轮换 | 降低长期暴露窗口 | 不能代替紧急吊销与可靠自动化 |
现实客户端可能采用 hard-fail、soft-fail、浏览器自有吊销列表或其他策略。openssl s_client 显示 Verify return code: 0 不等于已经按浏览器策略完成在线 OCSP/CRL 检查;必须明确工具参数、网络可达性和验证策略。
十二、HSTS 与 HTTPS 强制
HTTP 严格传输安全(HTTP Strict Transport Security,HSTS)通过 HTTPS 响应头告诉支持的用户代理,在有效期内只使用 HTTPS:
Strict-Transport-Security: max-age=31536000; includeSubDomains浏览器收到后会把后续 http:// 导航内部升级为 HTTPS,并拒绝绕过严重证书错误。边界:
- HSTS 头必须通过可信 HTTPS 获得;HTTP 响应中的该字段无效。
- 用户首次访问在无缓存策略时仍可能经过 HTTP,预加载列表可缓解,但它是浏览器生态机制。
includeSubDomains前必须确认所有子域均支持 HTTPS。- 超长
max-age和预加载难以快速撤销,发布前需完成全域证书与回滚设计。 - HSTS 不修复证书过期、名称错误或服务不可达。
十三、从 URL 到 HTTPS 响应
以 https://example.com/ 为例:
失败域必须按阶段区分:
| 阶段 | 典型失败 | 证据 |
|---|---|---|
| URL/代理策略 | scheme、端口或代理选择错误 | 应用配置、环境变量、PAC |
| DNS | NXDOMAIN、SERVFAIL、错误地址 | dig、系统解析日志 |
| IP/传输 | 超时、RST、UDP 被阻断 | ping 仅辅助;TCP/QUIC 抓包与 socket 错误 |
| TLS 协商 | 版本/cipher/group/ALPN 无交集 | TLS alert、ClientHello/ServerHello |
| PKI/身份 | 缺链、不信任、过期、SAN 不匹配 | 客户端验证错误、证书字段 |
| HTTP | 4xx/5xx、缓存或代理问题 | 状态码、字段、服务日志 |
| 业务 | 慢查询、依赖失败、逻辑错误 | trace、应用日志、指标 |
1、时延拆分
curl 的时间字段是从请求起点开始的累计时间:
curl -sS -o /dev/null \
-w 'dns=%{time_namelookup}s connect=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s http=%{http_version}\n' \
https://example.com/本机 curl 8.7.1 于 2026-09-07 的单次真实观测:
dns=0.003894s
connect=0.109261s
tls=0.222404s
ttfb=0.352832s
http_version=2正确计算增量:
DNS = time_namelookup
TCP ≈ time_connect - time_namelookup
TLS ≈ time_appconnect - time_connect
HTTP/服务 ≈ time_starttransfer - time_appconnect
下载 ≈ time_total - time_starttransfer该样本受本机 DNS 缓存、连接新旧、代理、路由、服务器负载和测量时刻影响,不能当成 SLA(Service-Level Agreement,服务等级协议)或协议性能结论。生产应按地域、网络、协议版本、冷/热连接统计 p50/p95/p99。
十四、最小可复现实验
1、查看公网握手、证书与 ALPN
环境:macOS 26.6.2,LibreSSL 3.3.6,目标为 IANA 保留文档域名 example.com。
openssl version
openssl s_client \
-connect example.com:443 \
-servername example.com \
-alpn h2,http/1.1 \
-tls1_3 </dev/null 2>&1 |
grep -E 'Protocol|Cipher is|ALPN protocol|Verify return code|subject=|issuer='本机真实输出节选:
LibreSSL 3.3.6
subject=/CN=example.com
issuer=/C=US/O=SSL Corporation/CN=Cloudflare TLS Issuing ECC CA 3
Cipher is AEAD-CHACHA20-POLY1305-SHA256
ALPN protocol: h2
Protocol: TLSv1.3
Verify return code: 0 (ok)证书、签发链和密码套件会随服务轮换、CDN 节点和客户端能力改变,该输出只代表本次观测。
查看证书字段:
openssl s_client \
-connect example.com:443 \
-servername example.com </dev/null 2>/dev/null |
openssl x509 -noout -subject -issuer -serial -dates -fingerprint -sha256
openssl s_client \
-connect example.com:443 \
-servername example.com </dev/null 2>/dev/null |
openssl x509 -noout -text |
sed -n '/Subject Alternative Name/{n;p;}'本机真实输出节选:
notBefore=Jul 29 22:10:08 2026 GMT
notAfter=Oct 27 22:17:21 2026 GMT
DNS:example.com, DNS:*.example.coms_client 是诊断工具。没有 -verify_return_error 时,它可能在验证错误后继续握手;不同 OpenSSL/LibreSSL 版本的验证和输出参数也不同。业务校验必须使用客户端库的严格验证 API,不能只 grep CONNECTED。
2、本地证书与主机名失败注入
目标:证明“证书被信任”与“目标身份匹配”是两项独立检查。
创建仅含 DNS:localhost 的一天期自签名实验叶证书:
tmpdir="$(mktemp -d)"
cd "$tmpdir"
printf '%s\n' \
'[req]' \
'distinguished_name=dn' \
'x509_extensions=v3_req' \
'prompt=no' \
'[dn]' \
'CN=localhost' \
'[v3_req]' \
'subjectAltName=DNS:localhost' \
'basicConstraints=critical,CA:FALSE' \
'keyUsage=critical,digitalSignature,keyEncipherment' \
'extendedKeyUsage=serverAuth' > server.cnf
openssl req -x509 -newkey rsa:2048 -nodes -days 1 -sha256 \
-config server.cnf -extensions v3_req \
-keyout server.key -out server.crt
openssl s_server -accept 8443 \
-cert server.crt -key server.key -www >server.log 2>&1 &
server_pid=$!
sleep 1在同一终端先用匹配的 DNS 身份访问:
curl --noproxy '*' --cacert "$tmpdir/server.crt" \
-sS -o /dev/null \
-w 'code=%{response_code} verify=%{ssl_verify_result} http=%{http_version}\n' \
https://localhost:8443/本机真实输出:
code=200 verify=0 http=1再以 IP 身份访问同一服务:
curl --noproxy '*' --cacert "$tmpdir/server.crt" \
https://127.0.0.1:8443/本机真实失败:
curl: (60) SSL: no alternative certificate subject name matches target ipv4 address '127.0.0.1'这里 --cacert 已显式信任实验自签名证书,但其 SAN 没有 iPAddress:127.0.0.1,所以身份校验仍失败。不要用 -k/--insecure“修复”,它会跳过关键安全校验。
清理:
kill "$server_pid"
cd /
rm -rf "$tmpdir"仅删除自己刚创建且路径已确认的临时目录,禁止把未检查的变量传给 rm -rf。
3、抓包
当前环境无免密抓包权限,以下步骤未执行:
sudo tcpdump -i any -nn -s 0 -w tls-handshake.pcap \
'host 192.0.2.10 and (tcp port 443 or udp port 443)'Wireshark 显示过滤器:
tls.handshake
tls.alert_message
tls.handshake.extensions_server_name
tls.handshake.extensions_alpn_str
quicTLS 1.3 应用数据默认不可解密。受控实验可让客户端输出会话密钥日志供 Wireshark 使用,但密钥日志能解密会话内容,必须按敏感凭据保护并在实验后销毁,禁止用于未授权生产流量。
十五、常见失败与排障
| 现象 | 优先假设 | 验证方法 | 不应直接断言 |
|---|---|---|---|
| TCP 超时,无 ServerHello | 路由、防火墙、监听、SNI 前置代理 | 双端抓包、端口与路径检查 | “证书有问题” |
| 收到 RST | 对端/中间设备主动拒绝或无监听 | 双端时序和设备日志 | 单侧抓包无法唯一定位谁发出 |
protocol_version | 版本无交集或策略拒绝 | 强制 1.2/1.3 对比,查服务配置 | 应重新启用旧协议 |
handshake_failure | cipher/group/签名/客户端证书等多种原因 | 读取 alert 前后握手字段与服务日志 | 只凭一个 alert 确定唯一根因 |
unknown ca | 信任库缺根、私有 CA 未配置或链错误 | 查看客户端 trust store 和服务端链 | 把根证书塞进服务端响应即可 |
unable to get local issuer | 常见为中间链不完整或签发者不可得 | s_client -showcerts、独立 path validation | 所有客户端都会自动 AIA 下载 |
| hostname mismatch | URL 身份与 SAN 不符 | 检查 URL、SNI、SAN、代理改写 | CN 相同即可通过 |
| expired/not yet valid | 证书生命周期或客户端时间异常 | UTC 时间、各节点证书序列号 | 只在服务端改时间 |
| ALPN 不符 | 上层协议协商/转发错误 | 查看 ClientHello 与选择结果 | TLS 成功就代表 HTTP 正常 |
| mTLS certificate required | 客户端未发证书或 CA/用途不匹配 | CertificateRequest、网关日志、客户端链 | 普通 Bearer Token 可替代握手要求 |
分层命令
# 1. DNS
dig example.com A +short
dig example.com AAAA +short
# 2. TLS 握手、SNI、ALPN 与服务端证书
openssl s_client \
-connect example.com:443 \
-servername example.com \
-alpn h2,http/1.1 \
-showcerts </dev/null
# 3. 严格 HTTP 客户端验证和阶段时延
curl -vI --connect-timeout 5 --max-time 15 https://example.com/
# 4. 绕过 DNS 但保持 URL 身份/SNI,仅用于受控定位
curl --resolve example.com:443:192.0.2.10 https://example.com/最后一条使用 RFC 5737 文档地址作为命令模板,默认不可达;实际排障只能替换为已授权目标地址。--resolve 能隔离 DNS 结果,但不能证明原 DNS 路径健康。
十六、安全风险与加固
| 风险 | 条件/影响 | 加固 |
|---|---|---|
| 协议降级 | 攻击者干扰协商,服务仍接受旧版本/弱套件 | 禁用旧版本弱算法,保留 TLS 1.3 降级保护,监控协商分布 |
| 私钥泄露 | 可冒充服务;影响取决于算法、会话和密钥范围 | HSM/KMS、最小权限、轮换、吊销、事件响应 |
| CA 误签/信任根过宽 | 攻击者获得目标名称有效证书 | CAA、Certificate Transparency 监控、缩小私有信任域 |
| 证书误配 | 缺链、错误 SAN、过期、节点证书不一致 | 自动签发轮换、预发布验证、多节点巡检 |
| 0-RTT 重放 | 非幂等 early data 被重复执行 | 默认关闭敏感操作 0-RTT、anti-replay、业务幂等 |
| Session Ticket 密钥泄露 | 扩大恢复会话影响范围 | 短周期轮换、节点分区、密钥托管与审计 |
| SNI/流量元数据泄露 | 路径观察者推断访问目标/行为 | 评估 ECH、最小元数据、不要误称 TLS 完全匿名 |
| 跳过验证 | MITM 可用任意证书冒充服务 | 禁止 --insecure、关闭 hostname verification 或全信任 trust manager |
| TLS 终止后明文 | LB 到上游链路可被窃听/篡改 | 明确终止边界,内部 TLS/mTLS、网络分段与最小权限 |
证书和私钥部署要求:
- 私钥不进入 Git、镜像层、日志或工单正文。
- 文件权限和运行身份最小化,优先使用 KMS/HSM 或平台密钥托管。
- 自动轮换必须验证新证书已加载到所有节点,而非只验证文件已写入。
- 同时监控剩余有效期、链完整性、SAN、序列号、OCSP 状态与实际握手。
- 回滚不能恢复已泄露的旧私钥;此类事件必须重新签发并吊销。
十七、性能与容量
TLS 成本来自:
- 完整握手的 RTT 与证书签名/验证。
- 证书链字节数,尤其影响高 RTT、低带宽和 QUIC 初始放大限制场景。
- AEAD 加解密和记录处理。
- 连接数、会话票据、OCSP stapling 与密钥轮换状态。
- TLS 终止代理上的 CPU、内存、文件描述符和队列。
优化优先级:
- 先区分 DNS、TCP/QUIC、TLS、TTFB 和下载阶段。
- 启用经过验证的连接复用、TLS 1.3 和合理会话恢复。
- 发送完整但不冗余的中间证书链。
- 基于真实并发、握手率、证书算法和 p95/p99 压测。
- 0-RTT 只在业务语义允许时启用,不能为了少一个 RTT 牺牲一致性。
“TLS 很慢”不是可执行结论。若 time_appconnect - time_connect 正常而 TTFB 高,应转向 HTTP/应用/依赖排查。
十八、版本与实现差异
- OpenSSL、LibreSSL、BoringSSL、Schannel、Secure Transport/Network.framework 和各语言 TLS 库支持的版本、groups、验证 API 与输出不同。
- macOS 系统
openssl可能是 LibreSSL,部分 OpenSSL 1.1.1/3.x 参数不可用;执行前先看openssl version和子命令帮助。 - 浏览器维护自己的证书验证、吊销、CT、HSTS preload 和连接策略,不能用一次
openssl s_client完全模拟。 - Java、容器基础镜像和操作系统可能使用不同 trust store;“浏览器能访问、Java 失败”常是信任库或链构建差异。
- TLS 1.3 支持不代表应用启用 HTTP/2/3;HTTP/2 依赖 ALPN
h2,HTTP/3 使用 QUIC/UDP 并通过自己的发现和回退路径。 - RFC 9525 已取代 RFC 6125 的通用服务身份建议;遗留库仍可能回退 CN,不能据此降低新系统要求。
十九、检查清单
- [ ] URL、代理、DNS 地址和实际连接目标一致。
- [ ] 支持 TLS 1.3;兼容所需 TLS 1.2 配置符合 RFC 9325。
- [ ] 禁用 SSLv2/3、TLS 1.0/1.1、静态 RSA 密钥交换和弱算法。
- [ ] 服务端发送叶证书和必要中间证书,不依赖客户端临时下载。
- [ ] SAN 覆盖全部目标 DNS/IP 身份,未依赖 CN 回退。
- [ ] 证书时间、EKU、KeyUsage、BasicConstraints 与签名链有效。
- [ ] 明确 OCSP/CRL/Stapling 的客户端和服务端策略。
- [ ] SNI 选择正确证书,ALPN 选择与上层协议一致。
- [ ] Session Ticket 密钥有轮换、隔离和失效机制。
- [ ] 0-RTT 仅承载可安全重放的请求。
- [ ] mTLS 身份已映射到最小权限授权,而非“有证书即放行”。
- [ ] HSTS 覆盖范围和回滚风险已经验证。
- [ ] 监控真实握手的版本、失败率、时延、证书序列号与剩余有效期。
二十、关联章节
- 上一章:16 HTTP 语义、缓存与版本演进
- 相关:13 TCP 状态机、15 DNS、18 代理/LB/CDN、20 抓包与实验、网络安全、分层故障排查
检索关键词
TLS 1.2 TLS 1.3 握手 ClientHello ServerHello EncryptedExtensions CertificateVerify Finished ECDHE HKDF AEAD 前向保密 TLS record legacy_record_version PKI X.509 证书链 Trust Anchor SAN 主机名校验 RFC 9525 SNI 虚拟主机 ALPN h2 http/1.1 h3 OCSP CRL OCSP Stapling Session Ticket PSK 会话恢复 TLS 0-RTT 重放 mTLS 双向认证 HSTS curl time_appconnect TLS handshake failure 排障
权威来源
- RFC 8446:The Transport Layer Security (TLS) Protocol Version 1.3
- RFC 5246:TLS 1.2
- RFC 9325:Recommendations for Secure Use of TLS and DTLS
- RFC 5280:Internet X.509 Public Key Infrastructure Certificate and CRL Profile
- RFC 9525:Service Identity in TLS
- RFC 7301:TLS Application-Layer Protocol Negotiation Extension
- RFC 6960:Online Certificate Status Protocol
- RFC 6066:TLS Extensions(含 server_name)
- RFC 6797:HTTP Strict Transport Security
- IANA TLS Parameters
- IANA TLS ALPN Protocol IDs
TLS 1.3、PKIX 路径与服务身份规则已于 2026-09-07 对照 RFC 8446、5280、9525 和 9325 核验。公网
example.comTLS 1.3/ALPN/证书字段以及本地信任成功、SAN 不匹配失败均已真实执行;TLS/QUIC 抓包因当前无免密抓包权限而明确标记为未执行。
