mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1711 字
5 分钟
TLS 握手详解:从明文到加密通道
2023-04-27

前言#

当你在浏览器地址栏输入 https:// 开头的网址时,TCP 三次握手完成后,紧接着就是 TLS 握手。这一过程在几百毫秒内完成,却承担着身份验证、密钥协商、加密通信三重任务。本文深入剖析 TLS 1.2 和 TLS 1.3 的握手细节,揭开从明文到加密通道的全过程。

TLS 握手概览#

sequenceDiagram participant C as Client participant S as Server Note over C,S: TLS 1.2 完整握手(2-RTT) C->>S: ClientHello S->>C: ServerHello + Certificate + ServerKeyExchange + ServerHelloDone C->>S: ClientKeyExchange + ChangeCipherSpec + Finished S->>C: ChangeCipherSpec + Finished Note over C,S: 加密通信开始

一、TLS 协议栈#

1.1 TLS 在网络协议中的位置#

+-----------------------------------+
| Application | HTTP, FTP, SMTP
+-----------------------------------+
| TLS | 安全层
+-----------------+-----------------+
| Handshake | Record |
| Protocol | Protocol |
+-----------------+-----------------+
| TCP | 传输层
+-----------------------------------+
| IP | 网络层
+-----------------------------------+

1.2 TLS 协议组成#

协议用途端口号
Handshake协商密钥和参数-
ChangeCipherSpec通知启用加密-
Alert错误和警告通知-
Record数据分片和加密传输-
Application Data加密的应用数据443

1.3 TLS Record 结构#

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ContentType | Version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Fragment (plaintext) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

ContentType 取值

类型
20ChangeCipherSpec
21Alert
22Handshake
23Application Data

二、TLS 1.2 完整握手流程#

2.1 第一次往返:协商参数#

sequenceDiagram participant C as Client participant S as Server Note over C: 构造 ClientHello C->>S: ClientHello Note over S: 解析支持的版本和套件 Note over S: 选择最佳密码套件 S->>C: ServerHello S->>C: Certificate S->>C: ServerKeyExchange S->>C: ServerHelloDone

2.2 ClientHello 详解#

// ClientHello 消息结构
const clientHello = {
clientVersion: 0x0303, // TLS 1.2
random: {
gmt_unix_time: 1711065600,
random_bytes: "28字节的随机数",
},
session_id: "", // 首次连接为空
cipher_suites: [
0xC02F, // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
0xC030, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
0xC013, // TLS_RSA_WITH_AES_128_CBC_SHA
0xC014, // TLS_RSA_WITH_AES_256_CBC_SHA
],
compression_methods: [0x00], // 无压缩
extensions: {
server_name: "example.com",
ec_point_formats: [0x00], // uncompressed
elliptic_curves: [0x001D, 0x0017, 0x0018], // x25519, secp256r1, secp384r1
signature_algorithms: [
{ hash: "SHA256", sign: "RSA" },
{ hash: "SHA384", sign: "RSA" },
{ hash: "SHA256", sign: "ECDSA" },
],
session_ticket: "", // 空表示支持但不持有
},
};

ClientHello 抓包示例

TLSv1.2 ClientHello
Version: TLS 1.2 (0x0303)
Random:
gmt_unix_time: Mar 22, 2026 08:00:00.000000000 CST
random_bytes: a3f2b8c1d4e5...
Session ID Length: 0
Cipher Suites (4 suites)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
Extensions:
server_name: example.com
supported_groups: x25519, secp256r1, secp384r1
signature_algorithms: rsa_pkcs1_sha256, ecdsa_secp256r1_sha256

2.3 ServerHello 详解#

flowchart TB A[收到 ClientHello] --> B[选择 TLS 版本] B --> C[从客户端列表选择密码套件] C --> D[选择压缩方法] D --> E[处理扩展] E --> F[生成 Server Random] F --> G[构造 ServerHello]

ServerHello 消息

TLSv1.2 ServerHello
Version: TLS 1.2 (0x0303)
Random:
gmt_unix_time: Mar 22, 2026 08:00:00.100000000 CST
random_bytes: 7e3a1b9c2d8f...
Session ID Length: 32
Session ID: 5a6b7c8d9e0f...
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC02F)
Compression Method: null (0x00)
Extensions:
renegotiation_info: (empty)
ec_point_formats: uncompressed

2.4 证书与密钥交换#

sequenceDiagram participant C as Client participant S as Server participant CA as CA 机构 Note over S: 发送证书链 S->>C: Certificate(服务器证书 + 中间 CA 证书) Note over C: 构建证书链到根 CA C->>CA: OCSP 查询(或使用 Stapling) CA->>C: 证书状态 Note over C: 验证证书有效性 Note over S: ECDHE 密钥交换 S->>C: ServerKeyExchange(ECDHE 参数 + 签名) Note over S: 生成临时椭圆曲线密钥对 Note over C: 验证签名,生成预主密钥

证书验证链

根 CA 证书(预装在操作系统/浏览器)
└── 中间 CA 证书
└── 服务器证书(example.com)
验证步骤:
1. 服务器证书的签发者 == 中间 CA 的主题
2. 中间 CA 证书的签发者 == 根 CA 的主题
3. 根 CA 证书在信任库中
4. 所有证书在有效期内
5. 证书未被吊销(CRL/OCSP)

2.5 密钥生成过程#

// TLS 1.2 ECDHE 密钥生成流程
// 1. 密钥交换
const serverECDH = generateECDHKeyPair("x25519");
// 服务端发送公钥 serverECDH.pubKey
const clientECDH = generateECDHKeyPair("x25519");
// 客户端发送公钥 clientECDH.pubKey
const preMasterSecret = computeSharedSecret(
clientECDH.privKey,
serverECDH.pubKey
);
// 2. 生成 Master Secret
const masterSecret = PRF(
preMasterSecret,
"master secret",
clientRandom + serverRandom
)[0..47]; // 48 字节
// 3. 扩展为密钥材料
const keyBlock = PRF(
masterSecret,
"key expansion",
serverRandom + clientRandom
);
// 4. 切分密钥材料
const clientWriteMACKey = keyBlock[0..19]; // 20 字节 HMAC-SHA1
const serverWriteMACKey = keyBlock[20..39];
const clientWriteKey = keyBlock[40..55]; // 16 字节 AES-128
const serverWriteKey = keyBlock[56..71];
const clientWriteIV = keyBlock[72..79]; // 8 字节(GCM 则为 4 字节 nonce)
const serverWriteIV = keyBlock[80..87];

2.6 Finished 消息#

sequenceDiagram participant C as Client participant S as Server Note over C: 用新密钥加密 C->>S: ChangeCipherSpec C->>S: Finished (verify_data) Note over S: 验证 verify_data Note over S: 用新密钥加密 S->>C: ChangeCipherSpec S->>C: Finished (verify_data) Note over C: 验证 verify_data Note over C,S: 加密通道建立完成

verify_data 的计算

// verify_data 验证握手完整性
const verifyData = PRF(
masterSecret,
"client finished",
Hash(handshakeMessages)
)[0..11]; // 12 字节
// Hash 包含所有握手消息(不含 ChangeCipherSpec)
// 任何中间人篡改都会导致 verify_data 不匹配

三、密码套件详解#

3.1 密码套件命名规则#

TLS_<密钥交换算法>_<身份验证算法>_WITH_<加密算法>_<MAC算法>
示例:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
├─────┤ ├───┤ ├──┤ ├───┤
│ │ │ │
密钥交换 认证 加密 哈希/AEAD

3.2 各组件详解#

组件可选值说明
密钥交换RSA, DHE, ECDHE, PSK如何协商预主密钥
身份验证RSA, ECDSA, DSS证书签名算法
加密算法AES-128, AES-256, CHACHA20对称加密
MAC/AEADSHA256, SHA384, GCM, POLY1305消息认证

3.3 常见密码套件对比#

密码套件安全等级性能PFS
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256推荐
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384推荐
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256推荐
TLS_RSA_WITH_AES_128_CBC_SHA不安全
TLS_RSA_WITH_AES_256_CBC_SHA不安全

四、密钥交换算法#

4.1 RSA 密钥交换#

sequenceDiagram participant C as Client participant S as Server Note over C: 生成 48 字节预主密钥 Note over C: 用服务器公钥加密 C->>S: ClientKeyExchange(加密的预主密钥) Note over S: 用私钥解密得到预主密钥 Note over C,S: 双方计算主密钥

RSA 密钥交换的致命缺陷:没有前向保密。服务器私钥一旦泄露,所有历史流量都可被解密。

攻击场景:
1. 攻击者录制所有加密流量
2. 一年后服务器私钥泄露
3. 攻击者用私钥解密所有历史流量中的预主密钥
4. 由预主密钥推导出会话密钥
5. 解密所有历史通信内容

4.2 DHE 密钥交换#

// Diffie-Hellman 密钥交换
// 公共参数:p(大素数), g(生成元)
// 服务端
const serverPrivate = randomBigInt(); // a
const serverPublic = pow(g, serverPrivate) % p; // g^a mod p
// 客户端
const clientPrivate = randomBigInt(); // b
const clientPublic = pow(g, clientPrivate) % p; // g^b mod p
// 双方计算共享密钥
const sharedSecret_server = pow(clientPublic, serverPrivate) % p; // (g^b)^a mod p
const sharedSecret_client = pow(serverPublic, clientPrivate) % p; // (g^a)^b mod p
// g^(ab) mod p == g^(ba) mod p

DHE 参数交换

ServerKeyExchange 消息(DHE):
dh_p: 大素数 p(2048 bits)
dh_g: 生成元 g(通常为 2)
dh_Ys: 服务端公钥 g^a mod p
signature: 用服务器私钥对上述参数的签名

4.3 ECDHE 密钥交换#

flowchart LR subgraph 服务端 A[选择曲线 x25519] --> B[生成临时密钥对] B --> C[发送公钥 Q_s + 签名] end subgraph 客户端 D[验证签名] --> E[生成临时密钥对] E --> F[发送公钥 Q_c] F --> G[计算共享密钥] end C --> D G --> H[预主密钥 = ECDH<br/>共享密钥]

常用椭圆曲线

曲线名称位长安全等级备注
x25519255128-bit推荐,速度快
secp256r1256128-bit也称 P-256
secp384r1384192-bit也称 P-384
secp521r1521256-bit也称 P-521
// Go 标准库 ECDHE 密钥交换
// 参考: https://github.com/golang/go/blob/go1.25.0/src/crypto/tls/key_agreement.go
func (ka *ecdheKeyAgreement) generateServerKeyShare(config *Config, version uint16) error {
// 选择曲线
curveID := ka.curveID
// 生成临时密钥对
key, err := generateECDHEKey(curveID)
if err != nil {
return err
}
ka.key = key
return nil
}
func (ka *ecdheKeyAgreement) processClientKeyShare(curveID CurveID, clientPublic []byte) ([]byte, error) {
// 计算共享密钥
sharedKey, err := ka.key.ECDH(clientPublic)
if err != nil {
return nil, err
}
return sharedKey, nil
}

五、TLS 1.3 握手改进#

5.1 TLS 1.3 vs TLS 1.2#

flowchart TB subgraph "TLS 1.2(2-RTT)" direction LR A1[1. ClientHello] --> A2[2. ServerHello + Cert + KeyExchange] A2 --> A3[3. ClientKeyExchange + CCS + Finished] A3 --> A4[4. CCS + Finished] end subgraph "TLS 1.3(1-RTT)" direction LR B1[1. ClientHello + KeyShare] --> B2[2. ServerHello + KeyShare + Cert + Finished] end

5.2 TLS 1.3 1-RTT 握手#

sequenceDiagram participant C as Client participant S as Server Note over C: 附带密钥共享参数 C->>S: ClientHello + KeyShare (x25519) Note over S: 选择密码套件和密钥共享 S->>C: ServerHello + KeyShare Note over C,S: 此刻双方已计算出共享密钥 S->>C: EncryptedExtensions S->>C: Certificate S->>C: CertificateVerify S->>C: Finished Note over C: 验证证书和 Finished C->>S: Finished Note over C,S: 加密通道建立(1-RTT) C->>S: Application Data S->>C: Application Data

关键改进

  1. ClientHello 携带 KeyShare:客户端提前猜测服务端支持的密钥交换参数
  2. ServerHello 后立即加密:服务端响应第一个报文后,后续全部加密
  3. 简化密码套件:只保留 AEAD 加密(GCM、CHACHA20-POLY1305)

5.3 TLS 1.3 0-RTT 握手#

sequenceDiagram participant C as Client participant S as Server Note over C,S: 之前的连接中保存了 PSK Note over C: 使用 PSK 提前计算密钥 C->>S: ClientHello + KeyShare + Early Data (0-RTT) Note over S: 使用 PSK 解密 Early Data S->>C: ServerHello + KeyShare S->>C: EncryptedExtensions S->>C: Finished C->>S: Finished Note over C,S: 后续数据使用新的握手密钥

0-RTT 的安全限制

特性1-RTT0-RTT
重放保护
前向保密仅 Early Data
适用请求所有幂等请求
连接唯一性每次独立依赖 PSK

5.4 TLS 1.3 密码套件#

TLS 1.3 大幅简化了密码套件,移除了不安全的算法:

TLS 1.3 支持的密码套件:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_CCM_SHA256
TLS_AES_128_CCM_8_SHA256
移除的算法:
RC4(已破解)
3DES(过时)
CBC 模式(易受填充 oracle 攻击)
RSA 密钥交换(无 PFS)
MD5/SHA-1(碰撞攻击)
DHE(性能差,1024-bit 不安全)
静态 ECDH(无 PFS)

六、完美前向保密(PFS)#

6.1 PFS 原理#

flowchart TB subgraph "无 PFS(RSA 密钥交换)" A1[预主密钥 = f(服务器私钥)] --> A2[会话密钥 = f(预主密钥)] A2 --> A3[私钥泄露 → 所有会话可解密] end subgraph "有 PFS(ECDHE 密钥交换)" B1[临时密钥对(每次连接不同)] --> B2[预主密钥 = f(临时私钥, 对方临时公钥)] B2 --> B3[临时私钥用后即毁] B3 --> B4[私钥泄露 → 仅影响当前会话] end

6.2 临时密钥的生命周期#

连接 1: ECDHE 密钥对 A → 共享密钥 K1(会话结束后销毁 A)
连接 2: ECDHE 密钥对 B → 共享密钥 K2(会话结束后销毁 B)
连接 3: ECDHE 密钥对 C → 共享密钥 K3(会话结束后销毁 C)
即使 K1 泄露,K2 和 K3 不受影响。
即使服务器长期私钥泄露,K1/K2/K3 均无法推导。

七、会话恢复#

7.1 Session ID#

sequenceDiagram participant C as Client participant S as Server Note over C,S: 首次连接 C->>S: ClientHello (Session ID = 空) S->>C: ServerHello (Session ID = ABC123) Note over S: 缓存会话状态 {Session ID, Master Secret} Note over C,S: 完整握手... Note over C,S: 恢复连接 C->>S: ClientHello (Session ID = ABC123) Note over S: 查找缓存 S->>C: ServerHello (Session ID = ABC123) Note over C,S: 跳过密钥交换 C->>S: ChangeCipherSpec + Finished S->>C: ChangeCipherSpec + Finished Note over C,S: 1-RTT 恢复

Session ID 的限制

  • 服务端必须存储所有会话状态
  • 集群环境下需要共享会话缓存
  • 内存开销随并发连接数线性增长

7.2 Session Ticket#

sequenceDiagram participant C as Client participant S as Server Note over C,S: 首次连接 C->>S: ClientHello (空 Session Ticket) Note over C,S: 完整握手... S->>C: NewSessionTicket Note over S: 用自身密钥加密会话状态 Note over C: 保存加密的 Ticket Note over C,S: 恢复连接 C->>S: ClientHello + Session Ticket Note over S: 解密 Ticket 恢复会话状态 S->>C: ServerHello C->>S: Finished S->>C: Finished
// Go 标准库 Session Ticket 处理
// 参考: https://github.com/golang/go/blob/go1.25.0/src/crypto/tls/ticket.go
type sessionState struct {
version uint16
cipherSuite uint16
createdAt uint64
masterSecret []byte
certificates [][]byte
}
func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
// 使用服务端配置的密钥加密 Ticket
encrypted := aesGCMSeal(c.config.SessionTicketKey, state)
return encrypted, nil
}
func (c *Conn) decryptTicket(encrypted []byte) ([]byte, error) {
// 解密 Ticket 恢复会话状态
state, err := aesGCMOpen(c.config.SessionTicketKey, encrypted)
if err != nil {
return nil, err // 解密失败,回退到完整握手
}
return state, nil
}

7.3 TLS 1.3 PSK#

// TLS 1.3 Pre-Shared Key
// 服务端发送 NewSessionTicket 消息
const newSessionTicket = {
ticket_lifetime: 7200, // 2 小时
ticket_age_add: 0x3A7B2C1D, // 随机偏移量(防客户端指纹)
ticket_nonce: Buffer.from("01"),
ticket: Buffer.from("加密的会话数据"),
extensions: {},
};
// 客户端恢复时发送 pre_shared_key 扩展
const clientHello = {
// ... 其他字段
extensions: {
pre_shared_key: {
identities: [
{
identity: newSessionTicket.ticket,
obfuscated_ticket_age:
(Date.now() - ticketReceivedTime + newSessionTicket.ticket_age_add) %
0xFFFFFFFF,
},
],
binders: [
hmac(psk, "ClientHello 的哈希前缀"), // 证明拥有 PSK
],
},
},
};

7.4 会话恢复方式对比#

方式服务端状态集群支持安全性TLS 版本
Session ID有状态需要共享1.2
Session Ticket无状态天然支持1.2
PSK (TLS 1.3)无状态天然支持最高1.3

八、安全性分析#

8.1 常见攻击与防御#

攻击名称目标原理防御
BEASTTLS 1.0CBC 模式 IV 可预测使用 TLS 1.1+
POODLESSL 3.0CBC 填充 oracle禁用 SSL 3.0
HeartbleedOpenSSL心跳扩展长度校验缺失修复 OpenSSL
LogjamDHE 512-bit强制降级到弱 DHE 参数使用 2048+ bit DHE
Sweet323DES/CBC64-bit 分组碰撞禁用 3DES
ROBOTRSA PKCS#1 v1.5RSA 填充 oracle 攻击禁用 RSA 密钥交换
DROWNSSLv2跨协议攻击 RSA禁用 SSLv2

8.2 BEAST 攻击原理#

flowchart LR A[攻击者已知明文 P1] --> B[猜测下一个字节 X] B --> C[构造 IV = P1 ⊕ X ⊕ 已知IV] C --> D[注入恶意请求] D --> E{猜测正确?} E -->|是| F[确认 X] E -->|否| G[尝试下一个猜测] G --> B

8.3 降级攻击防御#

// TLS 1.3 降级保护机制
// ServerHello.random 的最后 8 字节会被特殊标记
function detectDowngrade(serverHello, supportedVersion) {
const last8Bytes = serverHello.random.slice(24, 32);
if (supportedVersion === 0x0304) {
// 客户端支持 TLS 1.3
// 但服务端协商了 TLS 1.2
if (serverHello.version === 0x0303) {
// 检查是否有降级标记
const downgradeSentinel = Buffer.from("44 4F 57 4E 47 52 44 01", "hex");
if (last8Bytes.equals(downgradeSentinel)) {
// 服务端主动降级,合法
return;
}
// 攻击者强制降级,断开连接
throw new Error("降级攻击检测");
}
}
}

九、性能优化#

9.1 OCSP Stapling#

sequenceDiagram participant C as Client participant S as Server participant CA as CA OCSP Server Note over S: 定期获取 OCSP 响应 S->>CA: OCSP Request CA->>S: OCSP Response(签名) Note over C,S: TLS 握手 C->>S: ClientHello (status_request) S->>C: Certificate + CertificateStatus Note over C: 验证 OCSP 签名 Note over C: 无需直接联系 CA

OCSP Stapling 的好处

  • 客户端不需要额外请求 OCSP 服务器
  • 减少握手延迟(节省一次网络往返)
  • 避免隐私泄露(CA 不知道客户端访问了哪些站点)
# Nginx 启用 OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;

9.2 False Start#

sequenceDiagram participant C as Client participant S as Server C->>S: ClientHello S->>C: ServerHello + Certificate + ServerKeyExchange + ServerHelloDone Note over C: 计算密钥材料 C->>S: ClientKeyExchange + ChangeCipherSpec + Finished Note over C: False Start: 提前发送应用数据 C->>S: HTTP Request (提前加密发送) S->>C: ChangeCipherSpec + Finished + HTTP Response

False Start 条件

  1. 密码套件必须支持前向保密(ECDHE)
  2. 必须使用 AEAD 加密(GCM/CHACHA20)
  3. 服务端证书必须可信

9.3 优化建议#

# Nginx TLS 优化配置
# 使用 TLS 1.2 和 1.3
ssl_protocols TLSv1.2 TLSv1.3;
# 优先使用服务端密码套件顺序
ssl_prefer_server_ciphers on;
# 推荐密码套件
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
# 启用 Session Ticket
ssl_session_tickets on;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
# 启用 OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# 启用 0-RTT (TLS 1.3)
ssl_early_data on;

十、调试与诊断#

10.1 使用 OpenSSL 测试#

# 测试 TLS 握手
openssl s_client -connect example.com:443 -tls1_2
# 查看 TLS 1.3 握手
openssl s_client -connect example.com:443 -tls1_3
# 查看证书链
openssl s_client -connect example.com:443 -showcerts
# 测试特定密码套件
openssl s_client -connect example.com:443 \
-cipher 'ECDHE-RSA-AES128-GCM-SHA256'
# 测试 OCSP Stapling
openssl s_client -connect example.com:443 -status

10.2 使用 tcpdump 抓包#

# 抓取 TLS 握手
tcpdump -i eth0 'tcp port 443' -w tls_handshake.pcap
# 只看 ClientHello 和 ServerHello
tshark -r tls_handshake.pcap \
-Y "tls.handshake.type == 1 || tls.handshake.type == 2"
# 查看协商的密码套件
tshark -r tls_handshake.pcap \
-Y "tls.handshake.type == 2" \
-T fields -e tls.cipher_suite

10.3 使用 ssldiagnose#

# 检查服务器 TLS 配置
nmap --script ssl-enum-ciphers -p 443 example.com
# 使用 testssl.sh
testssl.sh example.com
# 在线检测
# https://www.ssllabs.com/ssltest/

FAQ#

Q1: TLS 和 SSL 的关系是什么?#

SSL(Secure Sockets Layer)是 TLS 的前身。SSL 3.0 之后,协议被 IETF 接管并重命名为 TLS 1.0。目前 SSL 已完全废弃,所有现代浏览器都使用 TLS。但由于历史原因,很多人仍习惯性地将 TLS 称为 SSL。

Q2: HTTPS 一定安全吗?#

HTTPS 只保证传输过程加密和服务器身份验证,不保证以下内容:

  • 服务器本身是否可信(钓鱼网站也可以有合法证书)
  • 客户端是否安全(恶意软件可能绕过 TLS)
  • 数据存储是否安全(服务器收到明文后如何处理)

Q3: TLS 1.3 为什么移除了 RSA 密钥交换?#

RSA 密钥交换没有前向保密(PFS)。如果服务器私钥泄露,攻击者可以解密所有用该密钥交换的历史流量。ECDHE 每次连接使用临时密钥对,即使长期私钥泄露也不会影响历史会话。

Q4: 自签名证书和 CA 签名证书有什么区别?#

加密能力相同,区别在于信任链。CA 签名证书由受信任的证书颁发机构签名,浏览器会自动信任。自签名证书需要用户手动确认信任,适合内部使用,不适合公开服务。

Q5: 0-RTT 有什么安全风险?#

0-RTT 的 Early Data 可能遭受重放攻击。攻击者截获 0-RTT 数据后可以重新发送,导致服务端重复执行非幂等操作(如支付请求)。因此 0-RTT 只适合幂等请求,或需要应用层额外做防重放处理。

Q6: 证书链验证为什么很重要?#

证书链从服务器证书追溯到根 CA。如果验证不完整,攻击者可以伪造证书冒充目标服务器。2011 年 DigiNotar CA 被入侵后签发了大量伪造证书,导致 Google、Yahoo 等网站的流量被中间人截获。

参考资料#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

TLS 握手详解:从明文到加密通道
https://blog.souloss.com/posts/principles/tls-handshake-explained/
作者
Souloss
发布于
2023-04-27
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时