公网环境使用 HTTPS 参考:使用 Certbot 获取 Let’s Encrypt 颁发的 TLS 证书 | ZYF.IM。
简介
HTTPS(HyperText Transfer Protocol Secure)是在 HTTP 之上通过 TLS/SSL 实现加密的安全通信协议,用来保护浏览器与服务器之间的数据机密性、完整性与身份可信性。
开始实验
mkcert 会在本地生成一套根 CA(包含根证书和私钥),并把根证书导入系统/浏览器的信任列表。随后,它用这套 CA 的私钥为 localhost 等域名签发服务器证书;因为根证书已被信任,浏览器访问时就会把服务器证书视为可信。
brew install mkcert
mkcert -install
mkcert localhost
# The certificate is at "./localhost.pem" and the key at "./localhost-key.pem" ✅
# vi default.conf
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/ssl/certs/localhost.pem;
ssl_certificate_key /etc/ssl/certs/localhost-key.pem;
# 只允许 TLSv1.2 和 TLSv1.3 协议,显示禁止 TLSv1.0 和 TLSv1.1 协议
ssl_protocols TLSv1.2 TLSv1.3;
# 只保留高强度、带身份验证、且不使用 MD5 的 TLS 1.2(及以下)套件
ssl_ciphers HIGH:!aNULL:!MD5;
# 优先使用服务器端加密套件
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
docker run -d --name nginx-ssl \
-p 8443:443 \
-v ./default.conf:/etc/nginx/conf.d/default.conf:ro \
-v ./localhost.pem:/etc/ssl/certs/localhost.pem:ro \
-v ./localhost-key.pem:/etc/ssl/certs/localhost-key.pem:ro \
nginx:alpine
# docker rm -f nginx-ssl
# docker container restart nginx-ssl
测试
游览器
游览器访问 https://localhost:8443/
,如果证书是绿色的,说明成功了。
curl
curl -I https://localhost:8443/
HTTP/1.1 200 OK
Server: nginx/1.29.0
Date: Fri, 27 Jun 2025 01:54:36 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 24 Jun 2025 17:57:38 GMT
Connection: keep-alive
ETag: "685ae712-267"
Accept-Ranges: bytes
# -v 显示详细信息,查看 TLS 版本
curl -I https://localhost:8443/ -v
...
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
...
深入探索
HTTP 的三大安全缺陷
网络早已布满监听、篡改与伪装。
- 明文传输。任何中间节点(Wi-Fi 热点、ISP、CDN、政府网关)都能直接读取用户名、密码、Cookie、表单内容等敏感信息。
- 缺少完整性保护。中间人可随意插入、删除或修改页面内容(广告注入、恶意脚本、暗链植入)。客户端亦无法察觉。
- 无法验证身份。客户端无法确认自己连接的是"真正的 server"。攻击者可通过 DNS 欺骗、ARP 攻击或流量劫持将流量导向钓鱼站点。
为什么需要 HTTPS
TLS 通过“加密 + 身份认证 + 完整性校验”应对上述风险。
- 加密(Confidentiality)。对称加密保护数据内容;密钥通过非对称算法安全协商。
- 数据完整性(Integrity)。MAC(消息鉴别码)或 AEAD 算法确保内容未被篡改。
- 身份认证(Authentication)。服务器出示数字证书;浏览器验证证书链与域名匹配。
MAC vs AEAD
- MAC 提供数据完整性与对称实体认证,需要与独立的加密步骤结合来保障机密性。
- Message Authentication Code
- 只负责“认证”,不加密数据;与加密算法解耦。典型实现是 HMAC-SHA1/HMAC-SHA256。
- AEAD 将“加密 + 认证”合二为一,接口更简单、实现更安全、性能更佳,是现代协议的首选。
- Authenticated Encryption with Associated Data
- 加密数据 + 认证数据
- 典型实现是 AES-GCM/ChaCha20-Poly1305
- 在 TLS/QUIC/Noise 等现代协议中,AEAD 已全面取代传统的 “MAC-then-Encrypt”。
证书类型
按层级角色:
- 根证书 (Root CA):最高级别,Subject = Issuer 自签名,预装在操作系统/浏览器的“根信任库”内,用于验证下级证书。
- 中级证书 (Intermediate CA):由根证书签名,用于验证下级证书。降低根密钥泄露风险。
- 最终实体证书 (End Entity Certificate):由中级证书签名,绑定具体域名或主体,用于验证服务器身份。
按验证级别:
- DV(Domain Validation)证书仅验证域名所有权,通过自动化流程颁发,价格低廉甚至免费(如 Let’s Encrypt)。
- OV(Organization Validation)证书需要验证组织实体信息,在浏览器证书详情中可查看公司名称。
- EV(Extended Validation)证书验证最为严格,地址栏会显示公司名称,但多数现代浏览器已弱化此功能的 UI 展示。
证书链
在 HTTPS、TLS、S/MIME 等基于 X.509 的公钥基础设施 (PKI) 中,任何一张服务器或用户证书都必须被“信任根 (Root CA)”间接或直接签名。 从根证书一路向下到最终实体证书所形成的“逐级签名”路径,就称为证书链,也叫信任链 (Chain of Trust)。
HTTPS 在网络堆栈中的位置
- HTTP/HTTPS 仍是应用层协议。
- TLS(Transport Layer Security)位于 HTTP 与 TCP 之间;它把上层的明文字节(HTTP 报文)加密后再交给 TCP。
- TCP 提供可靠的字节流;IP 负责寻址和路由;最底层是物理/链路层。
- HTTPS = HTTP over TLS over TCP over IP。
协议 | 主要职责 | 典型端口 |
---|---|---|
HTTP | 应用语义:URL、方法、头、状态码… | 80(无加密) |
TLS | 机密性、完整性、身份认证 | 443(惯例) |
TCP | 可靠传输、流量控制、重传 | 任意 (443) |
IP | 路由、分片、寻址 | — |
- HTTPS ≠ 新协议。它只是“HTTP 报文透过 TLS 隧道运输”的俗称。协议栈中依然能看到标准的 HTTP 语法,只是先被 TLS 加密,运输途中看不到明文。
- TLS 与 TCP 的独立性。TLS 不关心丢包、重传;这些由 TCP 处理。相反,TCP 不理解证书、握手;这些由 TLS 负责。
TLS 握手过程
客户端 服务器
|<--- SYN → SYN/ACK → ACK --->| 建立可靠的 TCP 连接
|--- ClientHello (TLS) --->| 浏览器发起 TLS 握手,告诉服务器自己支持的协议版本、密码套件、随机数(Client Random)等信息
|<-- ServerHello + 证书 ---|
|--- 密钥协商/Finished ------->|
|<-- Finished ----------------|
TLS 信道建立完成
|--- HTTP GET / ------------->|
|<-- HTTP/1.1 200 OK ---------|
sequenceDiagram
participant Client
participant Server
Client->>Server: ClientHello<br/>– 支持的 TLS 版本、随机数、加密套件
Server-->>Client: ServerHello<br/>– 选定版本/套件、随机数
Server-->>Client: Certificate
Server-->>Client: ServerHelloDone
Client->>Server: ClientKeyExchange<br/>– 预主密钥 (用公钥加密)
Client->>Server: ChangeCipherSpec
Client->>Server: Finished (用对称密钥加密)
Server-->>Client: ChangeCipherSpec
Server-->>Client: Finished
note over Client,Server: 之后开始对称加密的数据传输
- 双方首先协商算法与随机数;
- 客户端用服务器公钥加密预主密钥;
- 双方基于随机数与预主密钥生成会话密钥;
- 后续通信全部使用对称加密,提高效率。
TLS 1.3
TLS 1.3(RFC 8446)是在 2018 年 8 月正式发布的最新版本,相比 TLS 1.2 做了深度“瘦身+加速+强化安全”。
- TLS 1.3 把握手变成 1-RTT 并引入 0-RTT,显著降低延迟。
- 强制 ECDHE + AEAD + SHA-2,淘汰所有过时与高危算法,默认提供前向保密。
- 握手更多字段被加密,降低被动监听价值,同时带来运维与抓包新挑战。
- 配置侧仅需保留少量推荐套件 (TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256 等),比 TLS 1.2 更易运维。
RTT vs. 0-RTT
“RTT” 本身确实是一个时间量(Round-Trip Time),指数据包从客户端发出、到达服务端,再把响应返回客户端所经历的往返延迟,常用 毫秒 (ms) 表示。
在协议说明里看到的 “1-RTT 握手 / 2-RTT 握手” 属于约定俗成的缩写:把 “一次往返时间” 抽象成 “一次来回(round trip)” 这个计数单位来用。
证书与密钥
openssl version
# 看看证书
openssl x509 -in localhost.pem -noout -text
证书的结构:
Certificate:
|- Data:
|- Version: 3
|- Serial Number: ...
|- Signature Algorithm: sha256WithRSAEncryption
|- Issuer: O=mkcert development CA, OU=..., CN=mkcert ...
|- Validity:
|- Not Before: Jun 27 03:39:39 2025 GMT
|- Not After : Sep 27 03:39:39 2027 GMT
|- Subject: O=mkcert development CA, OU=...
|- Subject Public Key Info: <网站的公钥>
|- Public Key Algorithm: rsaEncryption
|- Public-Key: (2048 bit)
|- Modulus: <模数>
|- Exponent: 65537 (0x10001)
|- X509v3 extensions
|- Signature Algorithm: sha256WithRSAEncryption
|- Signature Value: <颁发机构(CA)用自己私钥算出的数字签名,浏览器用 CA 公钥验证>
在 RSA 体系里,公钥由两部分组成:
- n:模数 (Modulus)
- e:公钥指数 (Exponent)
# 导出公钥
openssl x509 -in localhost.pem -pubkey -noout > pubkey.pem
# 查看导出的公钥
openssl pkey -pubin -in pubkey.pem -text -noout
# 看看私钥里有什么
openssl rsa -in localhost-key.pem -text -noout
私钥的结构:
Private-Key: (2048 bit, 2 primes)
# 模 n = p × q
modulus: ...
# e 公钥指数
publicExponent: 65537 (0x10001)
# m = c^d mod n
privateExponent: ...
# p 和 q 是两个大质数
prime1: ...
prime2: ...
# exponent1 = d mod (p-1)
exponent1: ...
# exponent2 = d mod (q-1)
exponent2: ...
# coefficient = inv(q) mod p
coefficient: ...
HTTP/2
当前使用的是 HTTP/1.1,如何启用 HTTP/2,请移步 NGINX 启用 HTTP/2 | ZYF.IM。
HTTP/3
References
– EOF –