HTTPS握手是TLS协议驱动的加密协商过程,核心解决身份可信、通信保密、数据完整三大问题,包含ClientHello、ServerHello、Certificate、密钥交换等关键步骤,最终生成会话密钥启用对称加密通信。

HTTPS 握手到底发生了什么
HTTPS 不是“给 HTTP 加个 S”就完事了,它背后是 TLS 协议在驱动整个加密握手流程。浏览器访问 https://example.com 时,真正耗时、出错率高、且常被面试官深挖的,就是这几十毫秒里的密钥协商过程。
这个过程不是单纯“加密传输”,而是分阶段解决三个核心问题:身份可信(防冒充)、通信保密(防窃听)、数据完整(防篡改)。每一步都依赖前一步的结果,漏掉任意一环,TLS handshake failed 就会直接报错。
ClientHello 到 ServerHello 之间到底传了啥
第一次往返(TCP 连接建立后),客户端发 ClientHello,里面关键字段包括:supported_versions(TLS 1.2/1.3)、cipher_suites(比如 TLS_AES_128_GCM_SHA256)、key_share(TLS 1.3 中带临时公钥)和 server_name(SNI,决定服务器返回哪个证书)。
服务器回 ServerHello,从中能确认双方最终采用的协议版本、密码套件、以及是否启用 0-RTT(仅 TLS 1.3)。如果这里不匹配——比如客户端只支持 TLS 1.3,而 Nginx 配置里关掉了 ssl_protocols TLSv1.3,就会卡在握手第一轮,Chrome 控制台只显示 ERR_SSL_PROTOCOL_ERROR,没有更具体提示。
立即学习“前端免费学习笔记(深入)”;
-
ServerHello后紧跟着的是Certificate消息,证书链必须完整(含中间 CA),否则 iOS Safari 会直接拒绝连接 - TLS 1.2 中服务器还要发
ServerKeyExchange(如使用 DHE),而 TLS 1.3 把密钥交换逻辑合并进key_share,大幅减少往返 - 证书里的
Subject Alternative Name必须覆盖请求域名,Common Name在现代浏览器中已被忽略
为什么用非对称加密交换密钥,却不用它传数据
因为性能。RSA 或 ECDSA 解密操作比 AES 快不了多少,但吞吐量差两个数量级。所以 TLS 只用非对称加密做两件事:验证证书签名(确认服务器身份),以及安全传递一个临时生成的对称密钥(pre-master secret 或 shared_secret)。
真正传输 HTTP 请求/响应时,全部走 AES-GCM 或 ChaCha20 这类对称加密——它们能在 CPU 级别用指令加速(如 AES-NI),而且支持认证加密(AEAD),一次运算同时完成加密+完整性校验。
- 如果你在 Node.js 里用
https.createServer({ key, cert }),私钥key只用于签名和解密 pre-master secret,绝不参与后续 HTTP body 加密 - 抓包工具(如 Wireshark)能看到 TLS 握手明文,但之后所有应用层数据都是密文,除非你导入服务器私钥并启用 TLS 解密功能
- 所谓“HTTPS 破解”,本质是拿到私钥或中间人伪造证书(需用户手动信任恶意根证书)
前端能干预或观测 TLS 握手吗
不能直接控制,但可以通过几个有限接口感知结果。最常用的是 performance.getEntriesByType('navigation') 中的 nextHopProtocol 字段——如果是 h2 或 h3,说明已走 HTTPS(HTTP/2 和 HTTP/3 强制要求 TLS);secureConnectionStart 时间戳减去 connectStart 就是握手耗时。
注意:JavaScript 无法读取证书内容、无法触发重协商、也无法降级协议。任何声称“前端切换 TLS 版本”的代码都是误导。真正影响握手的,是服务端配置(Nginx/OpenSSL)、CDN 设置(Cloudflare 的 TLS 1.3 开关)、以及客户端环境(旧 Android WebView 可能不支持 ALPN,导致 HTTP/2 失败)。
实际排查时,优先用 curl -v https://yoursite.com 看 * TLSv1.3 (IN), TLS handshake 日志,再对比浏览器开发者工具的 “Security” 标签页——那里会明确标出证书有效期、签名算法、协商出的密码套件,比背原理管用得多。



















