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?
- 数据加密:防止数据被窃听
- 身份验证:确保连接到正确的服务器
- 数据完整性:防止数据被篡改
- SEO 优化:搜索引擎优先收录 HTTPS 站点
- 浏览器信任:现代浏览器标记 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 包含所有使用的域名。
小结
本章我们学习了:
- SSL/TLS 的基本概念
- 获取 SSL 证书的方式(Let's Encrypt、自签名、商业证书)
- 基本的 SSL 配置
- SSL 安全配置(协议、加密套件、会话缓存)
- 安全头配置(HSTS、X-Frame-Options 等)
- 性能优化(HTTP/2、SSL 缓冲区)
- 多域名和通配符证书
- 证书管理和调试
练习
- 使用 Let's Encrypt 为网站配置 HTTPS
- 配置 HTTP 到 HTTPS 的重定向
- 添加安全响应头
- 测试 SSL 配置的安全性