HTTPS协议详解——SSL/TLS握手、证书与加密通信

5 阅读14分钟

HTTPS协议详解——SSL/TLS握手、证书与加密通信

本文基于华为云 ECS 实战环境,在 server-2(139.9.119.225 / 192.168.0.225)上生成自签名证书、配置 Nginx HTTPS 服务,并通过 curl -v、openssl s_client、tcpdump 等工具深入分析 SSL/TLS 握手全过程。所有数据均来自真实生产环境操作,完整还原 HTTPS 加密通信的建立机制。

一、HTTPS协议概述

HTTPS(HyperText Transfer Protocol Secure)并非一个全新协议,而是 HTTP over TLS/SSL——即在 TLS 加密通道上传输 HTTP 数据。其核心目标是解决 HTTP 明文传输带来的三大安全隐患:

威胁HTTP 风险HTTPS 防护
窃听数据明文传输,中间人可嗅探TLS 加密,密文传输
篡改内容可被代理或路由器修改MAC/AEAD 完整性校验
伪造任何人都可以冒充服务端数字证书 + CA 信任链验证

HTTPS 默认使用 443 端口,在 TCP 三次握手完成后,额外增加 TLS 握手阶段,协商加密算法、交换密钥、验证证书,之后才进入 HTTP 通信。

二、加密基础

2.1 对称加密 vs 非对称加密

类型特点典型算法HTTPS 用途
对称加密加解密使用同一密钥,速度快AES, ChaCha20应用数据加密
非对称加密公钥加密/私钥解密,速度慢RSA, ECDSA, X25519密钥交换、数字签名

HTTPS 结合两者优势:先用非对称加密安全地协商出对称密钥(会话密钥),再用对称密钥加密后续所有应用数据。

2.2 数字证书与CA链

数字证书是将公钥与身份信息绑定的电子文档,由受信任的 CA(Certificate Authority)签发。其信任模型如下:

  根CA (Root CA)
    |
    +-- 中间CA (Intermediate CA)
          |
          +-- 网站证书 (server-2.example.com)
  • 根证书:自签名,预装在操作系统/浏览器中,是信任的起点
  • 中间证书:由根 CA 签发,用于签发终端证书
  • 终端证书:网站实际使用的证书,包含域名和公钥

本文使用自签名证书(自己签发自己),因此 Issuer = Subject,浏览器会显示安全警告。在生产环境中应使用 Let's Encrypt 等受信任 CA 签发的证书。

三、自签名证书生成

3.1 生成命令

在 server-2 上执行 openssl 命令生成自签名证书:

# 生成 RSA 2048 位自签名证书,有效期 365 天
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/server.key \
  -out /etc/nginx/ssl/server.crt \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=DevOps Lab/OU=IT/CN=server-2.example.com" \
  -addext "subjectAltName=DNS:server-2.example.com,IP:192.168.0.225"

关键参数解析:

参数说明
-x509生成自签名证书而非 CSR
-nodes不对私钥加密(Nginx 启动时无需输入密码)
-days 365有效期 365 天
-newkey rsa:2048生成 2048 位 RSA 密钥对
-subj证书主题信息(C=国家, ST=省, L=市, O=组织, OU=部门, CN=通用名称)
-addext添加扩展,指定 SAN(Subject Alternative Name)

3.2 证书信息

通过 openssl x509 查看证书详情:

openssl x509 -in /etc/nginx/ssl/server.crt -text -noout

真实输出(关键字段):

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            4e:28:3c:3f:fe:b9:c5:50:9d:05:5f:bf:fb:44:2d:96:48:58:04:9c
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, ST = Beijing, L = Beijing, O = DevOps Lab,
                OU = IT, CN = server-2.example.com
        Validity
            Not Before: Sep 17 04:03:18 2026 GMT
            Not After : Sep 17 04:03:18 2027 GMT
        Subject: C = CN, ST = Beijing, L = Beijing, O = DevOps Lab,
                 OU = IT, CN = server-2.example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)

SAN 扩展信息:

openssl x509 -in /etc/nginx/ssl/server.crt -text -noout | grep -E 'DNS:|IP:'

输出:

DNS:server-2.example.com, IP Address:192.168.0.225
字段说明
Version3 (0x2)X.509 v3 证书
Serial Number4e:28:3c:3f:...证书唯一序列号
Signature Algorithmsha256WithRSAEncryptionSHA256 签名 + RSA 加密
Issuerserver-2.example.com签发者(自签名,与 Subject 相同)
Not BeforeSep 17 04:03:18 2026 GMT生效时间
Not AfterSep 17 04:03:18 2027 GMT过期时间
Subjectserver-2.example.com证书主体
Public KeyRSA 2048 bit公钥算法和长度
SANDNS:server-2.example.com, IP:192.168.0.225备用名称(域名和IP)

SAN(Subject Alternative Name)是现代证书中域名匹配的核心机制。TLS 握手时,客户端会检查服务器证书的 SAN 字段是否包含请求的主机名,而非旧版 CN(Common Name)字段。

3.3 证书链验证

使用 openssl s_client 查看证书链:

openssl s_client -connect localhost:443 -showcerts < /dev/null

真实输出:

depth=0 C = CN, ST = Beijing, L = Beijing, O = DevOps Lab, OU = IT, CN = server-2.example.com
verify error:num=18:self-signed certificate
verify return:1
depth=0 C = CN, ST = Beijing, L = Beijing, O = DevOps Lab, OU = IT, CN = server-2.example.com
verify return:1
CONNECTED(00000003)
---
Certificate chain
 0 s:C = CN, ST = Beijing, L = Beijing, O = DevOps Lab, OU = IT, CN = server-2.example.com
   i:C = CN, ST = Beijing, L = Beijing, O = DevOps Lab, OU = IT, CN = server-2.example.com
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Sep 17 04:03:18 2026 GMT; NotAfter: Sep 17 04:03:18 2027 GMT

verify error:num=18:self-signed certificate 表明这是一个自签名证书,不被系统信任链认可。证书链深度 depth=0 说明只有一层(没有中间 CA),Issuer 和 Subject 完全相同。

四、SSL/TLS握手过程

4.1 TLS 1.3 握手详解

使用 curl -v 在 server-2 上发起 HTTPS 请求,观察完整的 TLS 1.3 握手:

curl -sk -v https://localhost/secure 2>&1

真实输出(握手部分):

* Connected to localhost (127.0.0.1) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [25 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [1021 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / RSASSA-PSS

4.2 逐消息解析

步骤方向消息类型大小说明
1OUTClient Hello512B客户端发送支持的密码套件、TLS版本、随机数
2INServer Hello122B服务端选定密码套件、发送随机数
3INEncrypted Extensions25B加密扩展(如 ALPN 协议协商)
4INCertificate1021B服务端证书链
5INCERT verify264B证书验证签名(证明持有私钥)
6INFinished52B服务端握手完成(含验证数据)
7OUTChange cipher spec1B客户端切换到加密模式
8OUTFinished52B客户端握手完成

最终协商结果:

  • TLS 版本: TLSv1.3
  • 密码套件: TLS_AES_256_GCM_SHA384(AES-256-GCM 对称加密 + SHA384 哈希)
  • 密钥交换: X25519(椭圆曲线 Diffie-Hellman)
  • 签名算法: RSASSA-PSS(RSA 证书签名验证)

4.3 TLS 1.3 握手时序图

  Client (server-2)                         Server (server-2:443)
       |                                          |
       |--- Client Hello (512B) ----------------->|
       |    支持的密码套件、TLS版本、客户端随机数    |
       |    (明文传输)                             |
       |                                          |
       |<-- Server Hello (122B) ------------------|
       |    选定密码套件、服务端随机数              |
       |    (明文传输,之后切换为加密)               |
       |                                          |
       |<-- Encrypted Extensions (25B) -----------|
       |<-- Certificate (1021B) ------------------|
       |<-- Certificate Verify (264B) ------------|
       |<-- Finished (52B) -----------------------|
       |    (以上全部加密传输)                      |
       |                                          |
       |--- Change Cipher Spec (1B) ------------->|
       |--- Finished (52B) ---------------------->|
       |    (客户端切换到加密模式)                   |
       |                                          |
       |<========= 加密通道建立完成 ===============>|
       |                                          |
       |<-- New Session Ticket (265B) x2 ---------|
       |    (会话恢复票据)                         |
       |                                          |
       |--- HTTP GET /secure (加密) ------------->|
       |<-- HTTP 200 OK (加密) -------------------|

TLS 1.3 的最大改进是将握手从 2-RTT 缩减到 1-RTT(首次连接)甚至 0-RTT(会话恢复)。Server Hello 之后的全部消息都已加密,大幅减少了明文信息暴露。

4.4 握手数据统计

openssl s_client 还报告了握手数据量:

SSL handshake has read 1564 bytes and written 373 bytes
  • 服务端 → 客户端:1564 字节(证书 1021B + Server Hello 122B + 其他握手消息)
  • 客户端 → 服务端:373 字节(Client Hello 512B 减去部分压缩 + Finished)

五、TLS 1.2 vs TLS 1.3

分别使用 -tls1_2-tls1_3 参数测试两个版本的握手:

# TLS 1.2
openssl s_client -connect localhost:443 -tls1_2 < /dev/null 2>&1 | head -30

# TLS 1.3
openssl s_client -connect localhost:443 -tls1_3 < /dev/null 2>&1 | head -30

两个版本均成功连接,证书链完全一致。关键差异对比:

特性TLS 1.2TLS 1.3
握手 RTT2-RTT1-RTT(0-RTT 恢复)
密钥交换RSA 或 ECDHE仅 ECDHE/DHE(前向安全)
证书消息明文传输加密传输
静态 RSA 密钥交换支持已移除
CBC 模式密码套件支持已移除
压缩支持已移除(防 CRIME 攻击)
会话恢复Session ID/TicketSession Ticket + PSK
Change Cipher Spec每次仅兼容性保留

TLS 1.3 移除了所有不安全的算法和特性,强制前向安全(Forward Secrecy)。即使服务端私钥泄露,已捕获的历史流量也无法被解密。

六、HTTP vs HTTPS 性能对比

6.1 计时测试

在 server-2 上对比 HTTP(80端口)与 HTTPS(443端口)的请求耗时:

# HTTP 计时
curl -s -o /dev/null -w 'HTTP Connect: %{time_connect}s\nHTTP TTFB: %{time_starttransfer}s\nHTTP Total: %{time_total}s\n' http://localhost/

# HTTPS 计时
curl -sk -o /dev/null -w 'HTTPS Connect: %{time_connect}s\nHTTPS SSL: %{time_appconnect}s\nHTTPS TTFB: %{time_starttransfer}s\nHTTPS Total: %{time_total}s\n' https://localhost/secure

真实输出:

=== HTTP (Port 80) ===
HTTP Connect: 0.000126s
HTTP TTFB:    0.000288s
HTTP Total:   0.000317s

=== HTTPS (Port 443) ===
HTTPS Connect: 0.000117s
HTTPS SSL:    0.003055s
HTTPS TTFB:   0.003149s
HTTPS Total:  0.003175s

6.2 耗时分解

阶段HTTPHTTPS差值说明
TCP 连接0.000126s0.000117s-0.000009s基本一致
SSL 握手-0.003055s+0.003055sHTTPS 额外开销
TTFB0.000288s0.003149s+0.002861s含 SSL 时间
总耗时0.000317s0.003175s+0.002858s约 10 倍

SSL 握手开销约 3 毫秒(0.003055s)。在本机回环测试中,这一开销几乎可以忽略。在跨网络场景中,TLS 1.3 的 1-RTT 握手通常只增加一个 RTT 的延迟(同城约 1-2ms,跨地域约 10-50ms)。

对于已建立连接的后续请求(HTTP Keep-Alive 或 TLS Session Resumption),SSL 开销可降至接近零。因此生产环境中建议启用 TLS 会话恢复和连接复用。

七、支持的加密套件

查看 OpenSSL 支持的加密套件:

openssl ciphers -v 'HIGH:!aNULL' | head -20

真实输出:

TLS_AES_256_GCM_SHA384         TLSv1.3 Kx=any   Au=any  Enc=AESGCM(256)            Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256   TLSv1.3 Kx=any   Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256         TLSv1.3 Kx=any   Au=any  Enc=AESGCM(128)            Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2 Kx=ECDH  Au=ECDSA Enc=AESGCM(256)           Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2 Kx=ECDH  Au=RSA  Enc=AESGCM(256)           Mac=AEAD
DHE-DSS-AES256-GCM-SHA384      TLSv1.2 Kx=DH    Au=DSS  Enc=AESGCM(256)           Mac=AEAD
DHE-RSA-AES256-GCM-SHA384      TLSv1.2 Kx=DH    Au=RSA  Enc=AESGCM(256)           Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305  TLSv1.2 Kx=ECDH  Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305    TLSv1.2 Kx=ECDH  Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-RSA-CHACHA20-POLY1305      TLSv1.2 Kx=DH    Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256  TLSv1.2 Kx=ECDH  Au=ECDSA Enc=AESGCM(128)           Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256    TLSv1.2 Kx=ECDH  Au=RSA  Enc=AESGCM(128)           Mac=AEAD

密码套件命名格式:密钥交换-认证-加密-MAC

组件说明示例值
Kx (Key Exchange)密钥交换算法ECDH, DH, any(TLS1.3)
Au (Authentication)认证算法RSA, ECDSA, any(TLS1.3)
Enc (Encryption)对称加密算法AESGCM(256), CHACHA20/POLY1305(256)
Mac (Message Auth)消息认证码AEAD(认证加密一体)

TLS 1.3 的密码套件命名简化为 TLS_加密_密钥长度_MAC,因为密钥交换和认证算法在协议层面固定。

八、HTTP到HTTPS重定向

8.1 Nginx重定向配置

在 Nginx 配置中,通过 80 端口的服务器块实现 HTTP 到 HTTPS 的 301 永久重定向:

server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

return 301 返回 HTTP 301 Moved Permanently 状态码,指示客户端使用 HTTPS 重新请求。$host 保留原始主机名,$request_uri 保留原始路径和查询参数。

8.2 重定向验证

测试 HTTP 请求的响应:

curl -s -I http://localhost/secure 2>&1

实际输出:

HTTP/1.1 404 Not Found
Server: nginx/1.24.0 (Ubuntu)
Date: Thu, 17 Sep 2026 04:03:23 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
X-Backend-Server: backend-1-192.168.0.225

此处返回 404 而非预期的 301,原因是 server-2 上已存在监听 80 端口的 Nginx 配置(反向代理配置),新配置中的 listen 80 块因服务器名称冲突被忽略。Nginx 启动时的警告日志也证实了这一点:

2026/09/17 12:03:18 [warn] 10126#10126: conflicting server name "_" on 0.0.0.0:80, ignored

在生产环境中,确保 80 端口仅由重定向配置独占,避免多个 server 块监听相同端口和 server_name 冲突。正确配置后,HTTP 请求将收到:

HTTP/1.1 301 Moved Permanently
Location: https://localhost/secure

九、跨服务器HTTPS验证

从 server-1(113.44.212.242)向 server-2(192.168.0.225)发起 HTTPS 请求,验证跨服务器 TLS 通信:

# 在 server-1 上执行
curl -sk -v https://192.168.0.225/secure 2>&1

真实输出:

*   Trying 192.168.0.225:443...
* Connected to 192.168.0.225 (192.168.0.225) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [21 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [1021 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519 / RSASSA-PSS
* Server certificate:
*  subject: C=CN; ST=Beijing; L=Beijing; O=DevOps Lab; OU=IT; CN=server-2.example.com
*  issuer: C=CN; ST=Beijing; L=Beijing; O=DevOps Lab; OU=IT; CN=server-2.example.com
*  SSL certificate verify result: self-signed certificate (18), continuing anyway.
* using HTTP/1.x
> GET /secure HTTP/1.1
> Host: 192.168.0.225
< HTTP/1.1 200 OK
< Strict-Transport-Security: max-age=31536000
< X-HTTPS: On
This is a secure HTTPS response! Protocol: HTTP/1.1 SSL: TLSv1.3 Cipher: TLS_AES_256_GCM_SHA384

跨服务器握手与本机一致,使用 TLS 1.3 和 TLS_AES_256_GCM_SHA384。-k 参数跳过了自签名证书验证(verify result: 18),响应中包含 HSTS 头和 X-HTTPS 标记。

十、Nginx SSL配置详解

10.1 完整配置

server-2 上的 Nginx HTTPS 配置:

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name _;
    return 301 https://$host$request_uri;
}

# HTTPS 服务
server {
    listen 443 ssl;
    server_name _;

    # 证书配置
    ssl_certificate     /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    # 协议与密码套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # 会话缓存
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location /secure {
        default_type text/plain;
        return 200 "This is a secure HTTPS response! Protocol: $server_protocol SSL: $ssl_protocol Cipher: $ssl_cipher";
    }

    # HSTS 安全头
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-HTTPS "On" always;
}

10.2 配置项详解

指令说明
ssl_certificateserver.crt证书文件路径
ssl_certificate_keyserver.key私钥文件路径
ssl_protocolsTLSv1.2 TLSv1.3启用的 TLS 版本(禁用不安全的 SSLv3/TLSv1.0/TLSv1.1)
ssl_ciphersHIGH:!aNULL:!MD5密码套件筛选(高强度、禁用匿名、禁用MD5)
ssl_prefer_server_cipherson服务端优先选择密码套件
ssl_session_cacheshared:SSL:10m共享会话缓存,10MB(约4万个会话)
ssl_session_timeout10m会话缓存超时 10 分钟
HSTSmax-age=31536000强制浏览器一年内使用 HTTPS

10.3 HSTS头部

响应中的 HSTS(HTTP Strict Transport Security)头部:

Strict-Transport-Security: max-age=31536000

HSTS 告知浏览器在 max-age 指定的时间(31536000秒=1年)内,始终使用 HTTPS 访问该站点,即使用户手动输入 HTTP 地址也不跳转。这是防止 SSL Strip 中间人攻击的有效手段。

十一、总结

本文通过真实操作数据,完整剖析了 HTTPS 协议的核心机制:

  1. 加密体系:非对称加密(RSA/X25519)协商密钥 + 对称加密(AES-256-GCM)传输数据
  2. 证书机制:自签名证书 RSA 2048 + SHA256 签名 + SAN 域名匹配,有效期 2026.09-2027.09
  3. TLS 1.3 握手:1-RTT 完成,Client Hello → Server Hello → 加密消息(证书/验证/Finished)
  4. 性能开销:SSL 握手仅增加约 3ms(本机回环),跨网络约为 1 个 RTT
  5. 安全配置:禁用旧版 TLS,启用 HSTS,配置会话缓存优化性能
  6. 跨服务器验证:server-1 到 server-2 的 TLS 1.3 通信正常,加密套件 TLS_AES_256_GCM_SHA384

在实际生产部署中,建议使用 Let's Encrypt 等受信任 CA 签发证书,启用 TLS 1.3,配置 OCSP Stapling 加速证书验证,并使用 ssl_session_cache 和 ssl_session_tickets 优化会话恢复性能。