跳到主要内容

HTTPS & TLS 协议:数字世界的加密盾牌

HTTPS (HyperText Transfer Protocol Secure) 的本质是 HTTP over TLS。它解决了 HTTP 在互联网"裸奔"的三大痛点:窃听、篡改、冒充。理解 HTTPS 和 TLS 协议对于构建安全的 Web 应用至关重要。

HTTP 的三大安全缺陷

在深入了解 HTTPS 之前,我们需要理解为什么 HTTP 不安全:

窃听风险

HTTP 数据以明文传输,任何中间节点(路由器、代理、ISP)都可以查看内容。

客户端 -> [明文] -> 路由器 -> [明文] -> ISP -> [明文] -> 服务器

攻击场景:公共 Wi-Fi 下的流量嗅探、ISP 注入广告、企业网络监控。

篡改风险

HTTP 数据可以被中间节点修改,接收方无法察觉。

原始响应:<script src="app.js">
篡改后:<script src="malicious.js"></script><script src="app.js">

攻击场景:ISP 注入广告脚本、恶意代理替换下载文件、运营商劫持。

冒充风险

HTTP 无法验证服务器身份,攻击者可以伪装成目标服务器。

用户访问 bank.com
攻击者伪装成 bank.com(DNS 劫持或钓鱼网站)
用户输入账号密码 -> 攻击者获取

攻击场景:钓鱼网站、DNS 劫持、中间人攻击。


HTTPS 的核心原理:混搭加密的艺术

HTTPS 通过 TLS/SSL 协议解决了上述三个问题。很多人以为 HTTPS 是靠一种加密算法解决的,其实它是 对称加密 + 非对称加密 的完美组合。

加密方式的分工

加密类型用途特点常用算法
非对称加密握手阶段交换密钥安全但计算开销大RSA, ECDHE
对称加密数据传输阶段高效,适合大量数据AES-GCM, ChaCha20
哈希算法完整性验证防篡改SHA-256, SHA-384

工作流程概览

1. 握手阶段(使用非对称加密)
客户端 ←→ 服务器:协商加密算法,安全交换"会话密钥"

2. 数据传输阶段(使用对称加密)
客户端 ←→ 服务器:使用会话密钥加密传输数据

3. 完整性验证(使用哈希算法)
每条消息附带 MAC(消息认证码),防止篡改

为什么这样设计?

性能考量:非对称加密(如 RSA)计算开销是对称加密(如 AES)的 1000 倍以上。如果全程使用非对称加密,HTTPS 会慢到无法使用。

安全考量:对称加密的密钥需要安全传递,这正是非对称加密擅长的场景。


TLS 1.3:现代 HTTPS 的黄金标准

TLS 1.3 于 2018 年发布(RFC 8446),是目前 HTTPS 的主流版本。它相比 TLS 1.2 有革命性的改进。

TLS 1.3 的核心改进

更快的握手:1-RTT

TLS 1.2 需要两次往返(2-RTT)完成握手,TLS 1.3 只需要一次。

TLS 1.2 握手流程(2-RTT):
ClientHello ──────────────────────>
<────────────── ServerHello
<────────────── Certificate
<────────────── ServerKeyExchange
<────────────── ServerHelloDone
ClientKeyExchange ────────────────>
ChangeCipherSpec ─────────────────>
Finished ─────────────────────────>
<────────────── ChangeCipherSpec
<────────────── Finished

TLS 1.3 握手流程(1-RTT):
ClientHello + KeyShare ───────────>
<────────────── ServerHello + KeyShare
<────────────── EncryptedExtensions
<────────────── Certificate
<────────────── CertificateVerify
<────────────── Finished
Finished ─────────────────────────>

0-RTT 恢复:极致性能

当客户端再次连接之前访问过的服务器时,可以使用 0-RTT 恢复,在第一个包中就发送应用数据:

ClientHello + EarlyData ───────────>
<────────────── ServerHello
<────────────── ...

注意事项:0-RTT 数据没有前向保密保护,且可能被重放。只适合幂等请求(如 GET)。

更强的安全性

TLS 1.3 彻底废弃了不安全的算法:

算法类型TLS 1.2 支持TLS 1.3 支持
对称加密AES-CBC, RC4AES-GCM, ChaCha20-Poly1305
密钥交换RSA, DH, ECDHECDHE, DHE
哈希算法MD5, SHA-1SHA-256, SHA-384
填充模式PKCS#1 v1.5PSS

完全前向保密(Forward Secrecy)

前向保密意味着:即使服务器的长期私钥泄露,之前加密通信的内容也无法被解密。

实现原理:TLS 1.3 强制使用临时密钥交换(ECDHE/DHE),每次会话生成新的临时密钥对。

长期密钥:用于签名验证(服务器证书中的公钥)
临时密钥:用于生成会话密钥(每次握手新生成)

会话密钥 = f(客户端临时私钥, 服务器临时公钥)
= f(服务器临时私钥, 客户端临时公钥)

TLS 1.3 握手详细过程


TLS 证书体系:信任的链条

HTTPS 的安全性依赖于证书体系。证书解决了"如何验证服务器身份"的问题。

什么是证书?

证书(Certificate)就像服务器的"身份证",由受信任的第三方(CA,证书颁发机构)签发。证书包含:

  • 服务器域名
  • 服务器公钥
  • 签发者信息(CA)
  • 有效期
  • CA 的数字签名

证书链(Certificate Chain)

证书不是单独存在的,而是一条信任链:

根证书 (Root CA)

└── 中间证书 (Intermediate CA)

└── 叶子证书 (End-Entity / 服务器证书)

验证流程

  1. 浏览器收到服务器证书
  2. 检查证书是否由可信 CA 签发(验证 CA 签名)
  3. 如果签发者是中间 CA,继续验证中间 CA 的证书
  4. 直到找到根 CA(操作系统/浏览器内置信任)

根证书的信任来源

根证书预置在操作系统和浏览器中:

系统/浏览器根证书来源
WindowsWindows Certificate Store
macOSKeychain Access
Linux/etc/ssl/certs/
Chrome使用系统根证书 + Chrome 自带
Firefox自己维护的根证书库

常见的证书错误

错误类型原因解决方法
证书过期证书超过有效期续签证书
域名不匹配证书域名与访问域名不同申请正确域名的证书
不受信任的颁发者自签名证书或 CA 不被信任使用正规 CA 或导入根证书
证书吊销证书已被 CA 吊销更换新证书
混合内容HTTPS 页面加载 HTTP 资源所有资源使用 HTTPS

证书透明度(Certificate Transparency)

为了防止 CA 错误签发证书,现代 HTTPS 使用 CT 日志:

  • CA 签发证书时,必须将证书提交到公开的 CT 日志
  • CT 日志是只能追加、不可篡改的公开记录
  • 浏览器验证证书时,检查证书是否在 CT 日志中

加密算法详解

密码套件(Cipher Suite)

密码套件定义了 TLS 连接使用的所有算法:

TLS_AES_128_GCM_SHA256
│ │ │ │ │
│ │ │ │ └── 哈希算法(用于 PRF 和 MAC)
│ │ │ └────── AEAD 模式(加密 + 认证)
│ │ └────────── 对称加密算法
│ └─────────────── 密钥长度(位)
└─────────────────── 协议版本

对称加密算法

算法密钥长度模式性能适用场景
AES-128-GCM128 位AEAD快(有硬件加速)通用场景
AES-256-GCM256 位AEAD略慢高安全要求
ChaCha20-Poly1305256 位AEAD快(无硬件加速时)移动设备

AEAD 模式:Authenticated Encryption with Associated Data,同时提供加密和完整性验证。

密钥交换算法

算法基于的数学问题密钥长度性能说明
ECDHE P-256椭圆曲线离散对数256 位TLS 1.3 默认
ECDHE P-384椭圆曲线离散对数384 位较慢高安全要求
ECDHE X25519椭圆曲线离散对数256 位现代曲线,推荐

X25519:Daniel J. Bernstein 设计的 Curve25519 变体,设计简洁、实现容易、性能优秀。


HTTPS 连接建立完整流程

结合前面的知识,完整的 HTTPS 连接建立过程如下:

1. TCP 三次握手
客户端 ──SYN──> 服务器
客户端 <──SYN+ACK── 服务器
客户端 ──ACK──> 服务器

2. TLS 1.3 握手
客户端 ──ClientHello + KeyShare──> 服务器
客户端 <──ServerHello + KeyShare── 服务器
客户端 <──Certificate + Verify── 服务器
客户端 <──Finished── 服务器
客户端 ──Finished──> 服务器

3. HTTP 请求响应
客户端 ──Encrypted(Request)──> 服务器
客户端 <──Encrypted(Response)── 服务器

性能开销分析

阶段RTT主要开销
TCP 握手1 RTT网络延迟
TLS 1.3 握手1 RTT密钥计算 + 证书验证
总计2 RTT-

TLS 1.2 对比:需要 3-4 RTT(TCP + TLS),TLS 1.3 节省了 1-2 RTT。


实战:配置 HTTPS

获取证书

Let's Encrypt(推荐)

Let's Encrypt 提供免费的自动化证书颁发:

# 使用 Certbot 获取证书
sudo certbot certonly --nginx -d example.com -d www.example.com

# 自动续期(证书有效期 90 天)
sudo certbot renew --dry-run # 测试续期

# 查看证书信息
sudo certbot certificates

acme.sh(更灵活)

# 安装
curl https://get.acme.sh | sh

# 申请证书
acme.sh --issue -d example.com --nginx

# 安装证书到指定位置
acme.sh --install-cert -d example.com \
--cert-file /etc/nginx/ssl/cert.pem \
--key-file /etc/nginx/ssl/key.pem \
--fullchain-file /etc/nginx/ssl/fullchain.pem \
--reloadcmd "nginx -s reload"

Nginx 配置(TLS 1.3)

server {
listen 443 ssl http2;
server_name example.com;

# 证书配置
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

# TLS 版本:只允许 1.2 和 1.3
ssl_protocols TLSv1.2 TLSv1.3;

# 密码套件(TLS 1.2 兼容)
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;
ssl_prefer_server_ciphers off;

# 会话缓存
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off; # 禁用 Session Ticket(增强前向保密)

# OCSP Stapling(加速证书验证)
ssl_stapling on;
ssl_stapling_verify on;

# HSTS(强制 HTTPS)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# 其他安全头部
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

location / {
proxy_pass http://backend;
}
}

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

Apache 配置

<VirtualHost *:443>
ServerName example.com

SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder off

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost>

HTTPS 性能优化

会话复用

Session ID 复用

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;

服务器缓存会话状态,客户端重连时发送 Session ID,服务器恢复会话,跳过完整握手。

Session Ticket

ssl_session_tickets on;
ssl_session_ticket_key /etc/nginx/ssl/ticket.key;

服务器将会话状态加密后发给客户端,客户端保存。重连时发送 Ticket,服务器解密恢复会话。

注意:Session Ticket 会略微降低前向保密性,需要权衡安全与性能。

OCSP Stapling

OCSP(Online Certificate Status Protocol)用于检查证书是否被吊销。传统方式是客户端向 CA 查询,增加延迟。

OCSP Stapling 让服务器预先获取 OCSP 响应,在握手时发送给客户端:

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;

HTTP/2 多路复用

HTTPS 开启 HTTP/2 后,多个请求可以在一个连接上并行处理,减少连接开销:

listen 443 ssl http2;

常见问题排查

证书链不完整

问题:部分客户端(特别是 Android)报证书错误。

原因:服务器只发送了叶子证书,没有发送中间证书。

解决:使用 fullchain.pem 而非 cert.pem

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

混合内容(Mixed Content)

问题:HTTPS 页面加载 HTTP 资源,浏览器报警告。

解决

  1. 所有资源使用 HTTPS
  2. 使用相对协议:<script src="//cdn.example.com/app.js">
  3. 设置 upgrade-insecure-requests CSP:
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

证书更新后未生效

问题:更新证书后,浏览器仍显示旧证书。

原因:浏览器或 CDN 缓存了旧证书。

解决

  1. 清除浏览器缓存
  2. CDN 刷新证书
  3. 重启 Web 服务器

HTTPS 的局限性

[!WARNING] HTTPS 只能保护"路途中"的安全,不能解决所有问题。

HTTPS 无法防护的威胁

威胁说明
钓鱼网站攻击者可以申请合法证书(如 g0ogle.com),HTTPS 无法识别
客户端入侵用户设备被植入恶意根证书,所有 HTTPS 都能被解密
服务端漏洞HTTPS 不防护 SQL 注入、XSS 等应用层攻击
社会工程HTTPS 无法防止用户被诱骗泄露密码

企业中间人证书

某些企业网络会部署中间人代理,要求员工安装企业根证书:

用户 ──HTTPS──> 代理(解密) ──HTTPS──> 目标网站

企业根证书签发的"伪造"证书

这种情况下,企业可以查看所有 HTTPS 内容。这是合法的安全监控手段,但也增加了被滥用的风险。


测试与验证

SSL Labs 测试

访问 SSL Labs 测试服务器 HTTPS 配置,重点关注:

  • 证书有效性
  • TLS 版本支持
  • 密码套件强度
  • 前向保密支持
  • 已知漏洞(如 Heartbleed)

命令行测试

# 测试 TLS 版本
openssl s_client -connect example.com:443 -tls1_3

# 查看证书信息
openssl s_client -connect example.com:443 -showcerts

# 测试密码套件
nmap --script ssl-enum-ciphers -p 443 example.com

# 测试证书过期
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates

总结

HTTPS 学习检查清单

  • 理解 HTTP 的三大安全缺陷
  • 理解对称加密与非对称加密的分工
  • 了解 TLS 1.3 相比 1.2 的改进
  • 理解证书链和信任验证流程
  • 能够正确配置 Nginx/Apache HTTPS
  • 了解 OCSP Stapling、HSTS 等优化
  • 知道 HTTPS 的局限性

关键要点回顾

  1. HTTPS = HTTP + TLS:解决窃听、篡改、冒充三大问题
  2. TLS 1.3:1-RTT 握手、前向保密、废弃不安全算法
  3. 证书体系:根证书 → 中间证书 → 叶子证书的信任链
  4. 性能优化:会话复用、OCSP Stapling、HTTP/2

[!TIP] 理解了加密通信,想不想知道如何实现实时的双向通信?请看 WebSocket 协议详解