7.5.1 HTTPS原理与证书体系

HTTPS 是在 HTTP 之上通过 TLS 提供加密、身份认证与数据完整性保护的协议栈。Nginx 常作为 TLS 终止点负责证书链下发与加密通信建立。本节聚焦原理与证书体系,并给出可执行示例、常用命令与排错思路。

HTTPS/TLS 原理草图

sequenceDiagram
    participant C as Client
    participant S as Nginx Server
    participant CA as CA
    C->>S: ClientHello(TLS版本/套件/SNI)
    S->>C: ServerHello(选择套件/证书链)
    C->>CA: 验证证书链与域名
    CA-->>C: 证书有效/无效
    C->>S: 密钥协商(ECDHE)
    S->>C: Finished
    C<->>S: 加密HTTP数据传输

证书体系与信任链
- 根证书 Root CA:预置在浏览器/系统信任库。
- 中间证书 Intermediate CA:由根 CA 签发,降低根证书暴露风险。
- 服务器证书 Leaf:绑定域名与公钥;应包含完整链(不含根)。
- 信任链校验:客户端从 Leaf 往上验证至受信任根。

核心概念与字段
- 公钥/私钥:私钥必须保密;公钥包含于证书。
- CSR:证书签名请求,包含主体与公钥信息。
- SAN:多域名支持字段,现代浏览器以 SAN 为准。
- 证书类型:DV/OV/EV,按业务合规与验证级别选择。


示例:本地生成测试证书(演示原理)#

仅用于学习/测试,生产请使用可信 CA(如 Let’s Encrypt)

1)生成私钥与 CSR

# 生成私钥
openssl genrsa -out /etc/nginx/ssl/demo.key 2048

# 生成 CSR(包含 SAN)
cat >/etc/nginx/ssl/openssl.cnf <<'EOF'
[ req ]
default_bits       = 2048
prompt             = no
default_md         = sha256
distinguished_name = dn
req_extensions     = req_ext

[ dn ]
C  = CN
ST = BJ
L  = Beijing
O  = DemoOrg
CN = demo.example.com

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = demo.example.com
DNS.2 = www.demo.example.com
EOF

openssl req -new -key /etc/nginx/ssl/demo.key \
  -out /etc/nginx/ssl/demo.csr -config /etc/nginx/ssl/openssl.cnf

2)自签发证书(学习用)

openssl x509 -req -in /etc/nginx/ssl/demo.csr \
  -signkey /etc/nginx/ssl/demo.key \
  -out /etc/nginx/ssl/demo.crt \
  -days 365 -extensions req_ext -extfile /etc/nginx/ssl/openssl.cnf

3)验证证书信息

# 查看证书基本信息
openssl x509 -in /etc/nginx/ssl/demo.crt -noout -text | head -n 30

# 验证 SAN 是否包含域名
openssl x509 -in /etc/nginx/ssl/demo.crt -noout -text | grep -A2 "Subject Alternative Name"

示例:TLS 连接与握手检查#

# 查看 TLS 版本与证书链
openssl s_client -connect demo.example.com:443 -servername demo.example.com -showcerts

# 仅测试 TLS 1.2 / 1.3
openssl s_client -connect demo.example.com:443 -tls1_2 -servername demo.example.com
openssl s_client -connect demo.example.com:443 -tls1_3 -servername demo.example.com

预期效果
- 输出中 Protocol 为 TLSv1.2/1.3
- Verify return code: 0 (ok) 表示证书链可信


Nginx 证书链文件示例(理解证书链)#

# 假设 CA 提供了证书链:server.crt + intermediate.crt
cat /etc/nginx/ssl/server.crt /etc/nginx/ssl/intermediate.crt \
  > /etc/nginx/ssl/fullchain.crt

常见排错与定位#

1)证书不受信任
- 原因:证书链不完整或使用自签证书
- 排查:

openssl s_client -connect demo.example.com:443 -servername demo.example.com -showcerts \
  | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > /tmp/chain.pem

# 验证链完整性(需提供受信根)
openssl verify -CAfile /etc/ssl/certs/ca-bundle.crt /tmp/chain.pem

2)域名不匹配
- 原因:证书 CN/SAN 不含访问域名
- 排查:

openssl x509 -in /etc/nginx/ssl/fullchain.crt -noout -text | grep -A2 "Subject Alternative Name"

3)协议/套件不兼容
- 原因:客户端不支持服务端 TLS 版本/套件
- 排查:

# 扫描支持的协议(nmapnmap --script ssl-enum-ciphers -p 443 demo.example.com

关键命令解释(理解用途)#

  • openssl genrsa:生成 RSA 私钥文件
  • openssl req -new:根据私钥生成 CSR
  • openssl x509 -req:签发证书(此处为自签)
  • openssl s_client:模拟客户端握手并查看证书链
  • openssl verify:验证证书链可信性

练习#

  1. 生成一个包含两个域名的证书(使用 SAN),验证是否包含正确域名。
  2. 使用 openssl s_client 连接一个公网 HTTPS 网站,记录其证书链中包含的证书数量。
  3. 使用 nmap --script ssl-enum-ciphers 检查本机 Nginx 的 TLS 版本与加密套件。