跳到主要内容

SSL/TLS 配置

本章将介绍如何配置 Nginx 实现 HTTPS,包括证书管理、安全配置和最佳实践。

SSL/TLS 基础

什么是 SSL/TLS?

SSL(Secure Sockets Layer)和 TLS(Transport Layer Security)是用于在互联网上加密通信的协议。HTTPS 是 HTTP 的安全版本,使用 SSL/TLS 加密。

HTTPS 通信流程:
客户端 服务器
| |
|--- 1. Client Hello (支持的加密算法) -------->|
| |
|<-- 2. Server Hello (选择的算法 + 证书) -----|
| |
|--- 3. 验证证书,生成密钥 -------------------->|
| |
|<=== 4. 加密通信 =============================>|

解释

  • 客户端和服务器通过握手过程建立安全连接
  • 服务器提供 SSL 证书证明身份
  • 双方协商加密算法,生成会话密钥
  • 后续通信使用会话密钥加密

为什么需要 HTTPS?

  1. 数据加密:防止数据被窃听
  2. 身份验证:确保连接到正确的服务器
  3. 数据完整性:防止数据被篡改
  4. SEO 优化:搜索引擎优先收录 HTTPS 站点
  5. 浏览器信任:现代浏览器标记 HTTP 为不安全

获取 SSL 证书

Let's Encrypt(免费)

Let's Encrypt 提供免费的 SSL 证书,有效期 90 天,可自动续期。

# 安装 Certbot
# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx -y

# CentOS/RHEL
sudo dnf install certbot python3-certbot-nginx -y

# 获取证书
sudo certbot --nginx -d example.com -d www.example.com

# 自动续期测试
sudo certbot renew --dry-run

# 自动续期(crontab)
0 12 * * * /usr/bin/certbot renew --quiet

解释

  • --nginx 让 Certbot 自动配置 Nginx
  • -d 指定域名
  • 证书到期前会自动续期

自签名证书(开发环境)

# 生成私钥
openssl genrsa -out server.key 2048

# 生成证书签名请求
openssl req -new -key server.key -out server.csr

# 生成自签名证书(有效期 365 天)
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

# 一步生成(开发用)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout server.key -out server.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Dev/CN=localhost"

购买商业证书

从 CA(证书颁发机构)购买:

  • DigiCert
  • Comodo/Sectigo
  • GlobalSign
  • GoDaddy

基本 SSL 配置

最小配置

server {
listen 443 ssl;
server_name example.com;

# 证书文件
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

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

location / {
try_files $uri $uri/ /index.html;
}
}

HTTPS 重定向

将所有 HTTP 请求重定向到 HTTPS:

# HTTP -> HTTPS 重定向
server {
listen 80;
server_name example.com www.example.com;

# 301 永久重定向
return 301 https://example.com$request_uri;
}

# HTTPS 服务器
server {
listen 443 ssl http2;
server_name example.com www.example.com;

ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

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

location / {
try_files $uri $uri/ /index.html;
}
}

SSL 安全配置

推荐配置

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

# 证书
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;

# 协议版本(只允许 TLS 1.2 和 1.3)
ssl_protocols TLSv1.2 TLSv1.3;

# 加密套件
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:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

# 优先使用服务器的加密套件
ssl_prefer_server_ciphers off;

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

# 禁用会话票据
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# 安全头
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}

配置详解

ssl_protocols

指定允许的 SSL/TLS 协议版本:

# 只允许安全的协议
ssl_protocols TLSv1.2 TLSv1.3;

# 禁用旧版本(SSLv3、TLSv1.0、TLSv1.1)
# 这些版本存在安全漏洞

解释

  • SSLv2/SSLv3:已废弃,存在严重漏洞
  • TLSv1.0/TLSv1.1:已过时,建议禁用
  • TLSv1.2:当前主流,安全可靠
  • TLSv1.3:最新版本,性能和安全性最佳

ssl_ciphers

指定加密套件:

# 高安全性配置
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';

解释

  • ECDHE:支持前向保密(PFS)
  • AES128-GCM/AES256-GCM:对称加密算法
  • SHA256/SHA384:哈希算法

ssl_session

会话缓存配置:

# 会话缓存
ssl_session_cache shared:SSL:10m; # 10MB 缓存,约 40000 个会话
ssl_session_timeout 1d; # 会话有效期 1 天

# 禁用会话票据(更安全)
ssl_session_tickets off;

OCSP Stapling

OCSP Stapling 提高 SSL 握手性能:

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/chain.pem; # 证书链
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

解释

  • OCSP Stapling 让服务器代替客户端查询证书状态
  • 减少客户端的 OCSP 查询,提高连接速度
  • ssl_trusted_certificate 包含中间证书

安全头配置

HSTS(HTTP Strict Transport Security)

强制浏览器使用 HTTPS:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

参数说明

  • max-age:HSTS 有效期(秒),建议至少 1 年
  • includeSubDomains:包含所有子域名
  • preload:允许加入浏览器预加载列表
注意

启用 HSTS 后,如果证书出问题或需要回退 HTTP,用户将无法访问网站。建议先测试后再启用。

其他安全头

# 防止点击劫持
add_header X-Frame-Options "SAMEORIGIN" always;

# 防止 MIME 类型嗅探
add_header X-Content-Type-Options "nosniff" always;

# XSS 保护
add_header X-XSS-Protection "1; mode=block" always;

# 引用策略
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# 权限策略
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

性能优化

HTTP/2

HTTP/2 提供更好的性能:

listen 443 ssl http2;

HTTP/2 优势

  • 多路复用:一个连接处理多个请求
  • 头部压缩:减少传输数据
  • 服务器推送:主动推送资源

SSL 缓冲区

# SSL 缓冲区大小
ssl_buffer_size 4k; # 默认 16k,小文件用 4k 更好

会话缓存

# 共享会话缓存
ssl_session_cache shared:SSL:50m; # 约 200000 个会话
ssl_session_timeout 1d;

多域名证书

单证书多域名

server {
listen 443 ssl;
server_name example.com www.example.com example.net www.example.net;

# 一个证书覆盖多个域名
ssl_certificate /etc/nginx/ssl/multi-domain.crt;
ssl_certificate_key /etc/nginx/ssl/multi-domain.key;
}

通配符证书

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

# 通配符证书
ssl_certificate /etc/nginx/ssl/wildcard.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/wildcard.example.com.key;
}

SNI(Server Name Indication)

Nginx 通过 SNI 支持多个 SSL 证书:

# 站点 1
server {
listen 443 ssl;
server_name site1.com;
ssl_certificate /etc/nginx/ssl/site1.crt;
ssl_certificate_key /etc/nginx/ssl/site1.key;
}

# 站点 2
server {
listen 443 ssl;
server_name site2.com;
ssl_certificate /etc/nginx/ssl/site2.crt;
ssl_certificate_key /etc/nginx/ssl/site2.key;
}

解释:SNI 允许在同一 IP 和端口上使用不同的 SSL 证书。

完整配置示例

# HTTP 重定向到 HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;

# Let's Encrypt 验证路径
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}

# 其他请求重定向
location / {
return 301 https://example.com$request_uri;
}
}

# HTTPS 服务器
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;

# 证书
ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/example.com/privkey.pem;

# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# 会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;

# 安全头
add_header Strict-Transport-Security "max-age=63072000; 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;

# 网站配置
root /var/www/example.com/public;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}

# 静态资源
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

# 日志
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}

证书管理

证书文件说明

文件说明
fullchain.pem完整证书链(服务器证书 + 中间证书)
privkey.pem私钥
chain.pem中间证书链(用于 OCSP Stapling)
cert.pem服务器证书

证书验证

# 查看证书信息
openssl x509 -in certificate.crt -text -noout

# 查看证书有效期
openssl x509 -in certificate.crt -noout -dates

# 验证证书链
openssl verify -CAfile chain.pem certificate.crt

# 测试 SSL 配置
openssl s_client -connect example.com:443

证书续期

# Certbot 自动续期
certbot renew

# 手动续期
certbot certonly --nginx -d example.com

# 检查续期
certbot certificates

调试和测试

SSL 测试工具

# 使用 openssl 测试
openssl s_client -connect example.com:443 -tls1_2

# 使用 nmap 检查 SSL 配置
nmap --script ssl-enum-ciphers -p 443 example.com

# 使用 curl 测试
curl -vI https://example.com

常见问题

1. 证书链不完整

# 使用 fullchain.pem 而不是 cert.pem
ssl_certificate /etc/nginx/ssl/fullchain.pem;

2. 混合内容警告

检查页面中的 HTTP 资源链接,改为 HTTPS。

3. 证书域名不匹配

确保证书的 Common Name 或 SAN 包含所有使用的域名。

小结

本章我们学习了:

  1. SSL/TLS 的基本概念
  2. 获取 SSL 证书的方式(Let's Encrypt、自签名、商业证书)
  3. 基本的 SSL 配置
  4. SSL 安全配置(协议、加密套件、会话缓存)
  5. 安全头配置(HSTS、X-Frame-Options 等)
  6. 性能优化(HTTP/2、SSL 缓冲区)
  7. 多域名和通配符证书
  8. 证书管理和调试

练习

  1. 使用 Let's Encrypt 为网站配置 HTTPS
  2. 配置 HTTP 到 HTTPS 的重定向
  3. 添加安全响应头
  4. 测试 SSL 配置的安全性

延伸阅读