一句话概括
HTTPS = HTTP + TLS。TLS 1.3 通过 ECDHE 协商共享会话密钥,通过数字证书和数字签名认证服务器身份,通过对称加密和 AEAD 认证标签保证数据机密性和完整性。
一、建立 TCP 连接
Client ------------------------ Server
TCP 三次握手
TCP 建立成功后,开始 TLS 握手。
二、TLS 握手(TLS 1.3)
整个流程:
Client Server
│ │
│-------------- ClientHello ----------------------->│
│ │
│<------------- ServerHello ------------------------│
│<--------- EncryptedExtensions --------------------│
│<------------- Certificate ------------------------│
│<---------- CertificateVerify ---------------------│
│<--------------- Finished -------------------------│
│ │
│---------------- Finished ------------------------>│
│ │
============== HTTPS连接建立成功 ======================
三、ClientHello
客户端发送:
ClientHello
├── TLS Version
├── Client Random
├── Cipher Suites
├── KeyShare(ECDHE公钥)
├── SNI
└── Extensions
作用:
① 告诉服务器:
- 支持哪些 TLS 版本
- 支持哪些加密算法
② 把自己的 ECDHE 公钥发送过去。
注意:
这里不是发送共享密钥。
四、ServerHello
服务器返回:
ServerHello
├── TLS Version
├── Server Random
├── Cipher Suite
└── KeyShare(ECDHE公钥)
至此:
双方拥有:
Client
私钥A
公钥A
Server
私钥B
公钥B
双方计算:
客户端:
私钥A + 公钥B
服务器:
私钥B + 公钥A
得到:
共享会话密钥(Session Key)
注意:
共享密钥从未在网络上传输,而是双方各自计算出来。
此时开始:
Handshake Key
用于加密后续握手消息。
五、Certificate(服务器证书)
服务器发送:
Certificate
├── 域名
├── 公钥
├── 有效期
├── CA
└── CA签名
注意:
Certificate 已经使用 Handshake Key 加密传输。
客户端收到以后:
验证:
CA是否合法
域名是否一致
证书是否过期
证书链是否可信
如果失败:
TLS Alert
关闭连接
成功以后:
客户端得到:
服务器公钥(PK)
六、CertificateVerify(身份认证)
这是很多面试官重点问的。
作用:
证明服务器真的拥有证书对应的私钥。
服务器首先计算:
Handshake Transcript
就是:
ClientHello
ServerHello
EncryptedExtensions
Certificate
所有握手消息。
注意:
不是字符串。
而是:
每个Handshake Message完整二进制编码
然后:
SHA256()
↓
Handshake Hash
例如:
ABCD1234
服务器:
使用私钥:
Sign(
ServerPrivateKey,
HandshakeHash
)
↓
Signature
发送:
CertificateVerify
└── Signature
客户端:
已经拥有:
Certificate里的公钥
因此:
Verify(
PublicKey,
HandshakeHash,
Signature
)
如果:
true
说明:
只有服务器拥有私钥。
服务器身份认证完成。
七、Finished(握手完整性校验)
CertificateVerify:
证明的是:
服务器身份
Finished:
证明的是:
双方拥有相同共享密钥
整个握手没有被修改
服务器:
利用:
共享会话密钥
计算:
verify_data =
HMAC(
HandshakeKey,
HandshakeHash
)
发送:
Finished
客户端:
也计算:
HMAC(
HandshakeKey,
HandshakeHash
)
一致:
OK
否则:
Alert
关闭连接
客户端随后也发送自己的 Finished,服务器完成相同验证。
八、开始发送 HTTP 数据
TLS 握手完成。
HTTP 请求:
GET /index
不会直接发送。
而是:
HTTP数据
│
▼
AES-GCM
(SessionKey)
│
▼
Ciphertext
Authentication Tag
发送:
Ciphertext
Tag
九、HTTP 如何防止篡改?
很多人容易误认为:
用数字签名。
实际上:
不是。
TLS 1.3:
HTTP 数据:
使用:
AES-GCM
或者
ChaCha20-Poly1305
属于:
AEAD
Authenticated Encryption
with Associated Data
它一次完成:
加密
+
认证
输入:
SessionKey
Nonce
HTTP数据
输出:
Ciphertext
+
Authentication Tag
服务器发送:
Ciphertext
Tag
客户端:
重新计算:
Tag
比较:
收到Tag
==
重新计算Tag
一致:
说明:
数据没有被修改。
否则:
直接丢弃。
注意:
这里:
不是数字签名。
而是:
Authentication Tag
十、HTTPS 中所有密钥的作用(重点)
| 密钥 | 谁拥有 | 用途 |
|---|---|---|
| CA私钥 | CA | 签发证书 |
| CA公钥 | 浏览器内置 | 验证证书 |
| 服务器私钥 | 服务器 | CertificateVerify 数字签名 |
| 服务器公钥 | Certificate | 验证服务器签名 |
| ECDHE临时私钥 | 双方各自 | 协商共享密钥 |
| ECDHE临时公钥 | 双方交换 | 协商共享密钥 |
| 共享会话密钥(Session Key) | 双方 | 加密握手消息、Finished 校验、加密 HTTP 数据 |
十一、面试最容易问的几个问题
① 为什么不用 RSA 加密 HTTP?
RSA 属于非对称算法,计算成本高,只适合身份认证和签名。HTTPS 使用 ECDHE 协商共享会话密钥,后续 HTTP 全部使用 AES-GCM、ChaCha20-Poly1305 等对称加密算法,因此性能更高。
② 为什么要 CertificateVerify?
因为证书是公开的,任何人都可以下载。
CertificateVerify 使用服务器私钥对握手消息摘要签名,客户端使用证书中的公钥验证,证明当前服务器真正拥有证书对应的私钥,而不是仅复制了一张证书。
③ 为什么握手消息也要 Hash?
因为要保护整个握手过程。
Handshake Hash 计算的是:
ClientHello ||
ServerHello ||
EncryptedExtensions ||
Certificate
...
所有握手消息的完整二进制内容。
任何一个字段被修改,Hash 都会变化,CertificateVerify 和 Finished 验证都会失败。
④ HTTPS 如何保证三大安全目标?
| 安全目标 | 实现方式 |
|---|---|
| 身份认证 | Certificate + CertificateVerify |
| 数据机密性 | ECDHE 协商共享会话密钥 + AES-GCM/ChaCha20-Poly1305 对称加密 |
| 数据完整性/防篡改 | 握手阶段:CertificateVerify + Finished;数据传输阶段:AEAD Authentication Tag |
面试最终总结(60 秒)
HTTPS 本质是 HTTP + TLS。客户端首先发起 ClientHello,双方通过 ECDHE 交换临时公钥,各自计算出相同的共享会话密钥。随后服务器发送数字证书,客户端验证证书的 CA 签名、域名和有效期。接着服务器使用证书对应的私钥对握手消息摘要进行数字签名(CertificateVerify),客户端使用证书中的公钥验证,确认服务器确实拥有私钥。双方再通过 Finished 使用共享会话密钥验证整个握手过程未被篡改且共享密钥一致。握手完成后,HTTP 数据全部使用共享会话密钥通过 AES-GCM 或 ChaCha20-Poly1305 等 AEAD 算法进行加密,并自动生成认证标签(Authentication Tag),接收方验证认证标签后再解密,因此 HTTPS 同时实现了身份认证、数据机密性和数据完整性。