HTTPS 与安全配置
2026/3/20大约 9 分钟
HTTPS 与安全配置
HTTPS 工作原理
SSL/TLS 握手过程
对称加密与非对称加密
| 类型 | 算法示例 | 特点 | 用途 |
|---|---|---|---|
| 对称加密 | AES、ChaCha20 | 加密解密用同一密钥,速度快 | 数据传输加密 |
| 非对称加密 | RSA、ECDSA | 公钥加密、私钥解密,速度慢 | 密钥交换、数字签名 |
TLS 采用混合加密:
- 使用非对称加密交换会话密钥
- 使用对称加密传输实际数据
数字证书与 CA
证书内容:
证书版本:V3
序列号:xxxx
签名算法:SHA256withRSA
颁发者:DigiCert Inc
有效期:2024-01-01 至 2025-01-01
主题:www.example.com
公钥:RSA 2048 bits
扩展:SAN、密钥用途等
签名:CA的数字签名
证书链验证:
根证书(Root CA) ──► 自签名,内置于操作系统/浏览器
│
▼
中间证书(Intermediate CA)──► 由根CA签发
│
▼
服务器证书(Server Certificate)──► 由中间CA签发
SSL 证书获取
Let's Encrypt 免费证书
# 安装 Certbot
# CentOS
sudo yum install -y epel-release
sudo yum install -y certbot python3-certbot-nginx
# Ubuntu
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
# 方式1:自动配置 Nginx(推荐)
sudo certbot --nginx -d example.com -d www.example.com
# 方式2:仅获取证书
sudo certbot certonly --nginx -d example.com -d www.example.com
# 方式3:使用 Webroot 方式(Nginx 已配置好 /.well-known/acme-challenge/)
sudo certbot certonly --webroot -w /var/www/html -d example.com
# 方式4:DNS 验证(适合通配符证书)
sudo certbot certonly --manual --preferred-challenges dns -d "*.example.com"
# 查看证书
sudo certbot certificates
# 测试续期
sudo certbot renew --dry-run
# 自动续期(Certbot 自动添加 cron 或 systemd timer)
# 手动添加 cron
echo "0 0,12 * * * root certbot renew --quiet" | sudo tee /etc/cron.d/certbot
证书文件位置:
/etc/letsencrypt/live/example.com/
├── fullchain.pem # 完整证书链(服务器证书 + 中间证书)
├── privkey.pem # 私钥
├── cert.pem # 服务器证书
└── chain.pem # 中间证书
自签名证书
# 创建证书目录
sudo mkdir -p /etc/nginx/ssl
# 生成私钥和证书(一步完成)
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/selfsigned.key \
-out /etc/nginx/ssl/selfsigned.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=IT/CN=example.com"
# 或分步生成:
# 1. 生成私钥
openssl genrsa -out server.key 2048
# 2. 生成证书签名请求(CSR)
openssl req -new -key server.key -out server.csr
# 3. 自签名
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# 生成 Diffie-Hellman 参数(增强安全性)
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
商业证书安装
# 商业证书通常包含:
# - example.com.crt (服务器证书)
# - example.com.key (私钥)
# - ca-bundle.crt (中间证书链)
# 合并证书链
cat example.com.crt ca-bundle.crt > /etc/nginx/ssl/fullchain.crt
# 设置权限
chmod 600 /etc/nginx/ssl/example.com.key
chmod 644 /etc/nginx/ssl/fullchain.crt
Nginx HTTPS 基础配置
最小配置
server {
listen 443 ssl;
server_name example.com;
# 证书文件
ssl_certificate /etc/nginx/ssl/fullchain.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
root /var/www/html;
index index.html;
}
完整 SSL 配置
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# === SSL 证书 ===
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 和 TLS 1.0/1.1)
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 on;
# === DH 参数 ===
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# === 椭圆曲线 ===
ssl_ecdh_curve X25519:secp384r1;
# === 站点配置 ===
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
TLS 版本说明
| 版本 | 状态 | 说明 |
|---|---|---|
| SSL 2.0 | 已废弃 | 存在严重安全漏洞,禁止使用 |
| SSL 3.0 | 已废弃 | POODLE 攻击,禁止使用 |
| TLS 1.0 | 已废弃 | 2020 年起被主流浏览器弃用 |
| TLS 1.1 | 已废弃 | 2020 年起被主流浏览器弃用 |
| TLS 1.2 | 推荐 | 目前主流,兼容性好 |
| TLS 1.3 | 推荐 | 最新版本,更快更安全 |
HTTPS 优化
SSL Session 缓存
http {
# 共享 SSL Session 缓存
# shared: 所有 worker 共享
# SSL: 缓存名称
# 10m: 10MB 缓存空间(约 4 万个 session)
ssl_session_cache shared:SSL:10m;
# Session 超时时间(默认 5 分钟)
ssl_session_timeout 1d;
# Session Tickets(无状态会话恢复)
ssl_session_tickets on;
# Session Ticket 密钥(48字节随机数据)
# 建议定期轮换
ssl_session_ticket_key /etc/nginx/ssl/ticket.key;
}
生成 ticket key:
openssl rand 48 > /etc/nginx/ssl/ticket.key
chmod 600 /etc/nginx/ssl/ticket.key
OCSP Stapling
server {
# 启用 OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
# 信任的 CA 证书(用于验证 OCSP 响应)
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# DNS 解析器(用于查询 OCSP 服务器)
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
}
验证 OCSP Stapling:
# 测试 OCSP Stapling 是否生效
openssl s_client -connect example.com:443 -status -servername example.com 2>/dev/null | grep -A 17 "OCSP Response"
HTTP/2 配置
server {
# HTTP/2 需要 HTTPS
listen 443 ssl http2;
# HTTP/2 服务器推送(可选)
http2_push_preload on;
location / {
# 预加载关键资源
add_header Link "</css/main.css>; rel=preload; as=style";
add_header Link "</js/main.js>; rel=preload; as=script";
}
}
HSTS(HTTP 严格传输安全)
server {
# HSTS 头
# max-age: 有效期(秒),建议至少 6 个月
# includeSubDomains: 包含子域名
# preload: 申请加入浏览器预加载列表
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}
HSTS 注意事项
- 确保所有子域名都支持 HTTPS 后再启用 includeSubDomains
- 启用 preload 后难以撤销,请谨慎
- 建议先使用较短的 max-age 测试,确认无误后再延长
:::
安全响应头详解
server {
# === X-Frame-Options ===
# 防止点击劫持(页面被嵌入 iframe)
# DENY: 完全禁止
# SAMEORIGIN: 只允许同源
# ALLOW-FROM uri: 允许指定来源(已废弃)
add_header X-Frame-Options "SAMEORIGIN" always;
# === X-Content-Type-Options ===
# 禁止浏览器猜测 MIME 类型
add_header X-Content-Type-Options "nosniff" always;
# === X-XSS-Protection ===
# 启用浏览器 XSS 过滤器(现代浏览器已内置,可选)
add_header X-XSS-Protection "1; mode=block" always;
# === Content-Security-Policy ===
# 内容安全策略,控制资源加载来源
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://api.example.com; frame-ancestors 'self';" always;
# === Referrer-Policy ===
# 控制 Referer 头的发送策略
# no-referrer: 不发送
# same-origin: 只对同源请求发送
# strict-origin-when-cross-origin: 推荐
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# === Permissions-Policy ===
# 控制浏览器功能权限(前身是 Feature-Policy)
add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" always;
# === X-Permitted-Cross-Domain-Policies ===
# 控制 Flash 和 PDF 的跨域策略
add_header X-Permitted-Cross-Domain-Policies "none" always;
}
HTTP 强制跳转 HTTPS
# 方法1:使用 return(推荐)
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# 方法2:使用 rewrite
server {
listen 80;
server_name example.com www.example.com;
rewrite ^(.*)$ https://$host$1 permanent;
}
# 方法3:使用 if(不推荐,但某些场景需要)
server {
listen 80;
server_name example.com;
if ($scheme = http) {
return 301 https://$host$request_uri;
}
}
# 方法4:同时监听 80 和 443
server {
listen 80;
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
if ($scheme = http) {
return 301 https://$host$request_uri;
}
# 其他配置...
}
双向 SSL 认证(mTLS)
server {
listen 443 ssl;
server_name api.example.com;
# 服务器证书
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# 客户端证书验证
ssl_client_certificate /etc/nginx/ssl/ca.crt; # CA 证书
ssl_verify_client on; # 强制验证客户端证书
# ssl_verify_client optional; # 可选验证
ssl_verify_depth 2; # 证书链验证深度
# 传递客户端证书信息给后端
location / {
proxy_pass http://backend;
proxy_set_header X-Client-Cert $ssl_client_cert;
proxy_set_header X-Client-S-DN $ssl_client_s_dn;
proxy_set_header X-Client-Verify $ssl_client_verify;
}
# 根据验证结果控制访问
location /api/ {
if ($ssl_client_verify != SUCCESS) {
return 403;
}
proxy_pass http://backend;
}
}
生成客户端证书:
# 1. 创建 CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -sha256 -days 3650 -key ca.key -out ca.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=CA/CN=My CA"
# 2. 创建客户端密钥
openssl genrsa -out client.key 2048
# 3. 创建客户端 CSR
openssl req -new -key client.key -out client.csr \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg/OU=Client/CN=client1"
# 4. 使用 CA 签发客户端证书
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out client.crt
# 5. 转换为 PKCS12 格式(浏览器导入用)
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12
安全最佳实践
隐藏 Nginx 版本号
http {
# 隐藏版本号
server_tokens off;
# 自定义 Server 头(需要 headers-more 模块)
# more_set_headers 'Server: MyServer';
}
禁止目录遍历和访问控制
server {
# 禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 禁止访问备份文件
location ~* \.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|old|orig)$ {
deny all;
access_log off;
log_not_found off;
}
# 禁止访问敏感目录
location ~ ^/(\.git|\.svn|\.hg|CVS) {
deny all;
}
# 禁止 PHP 文件执行(上传目录)
location /uploads/ {
location ~ \.php$ {
deny all;
}
}
}
限制请求方法
server {
# 只允许 GET、POST、HEAD
if ($request_method !~ ^(GET|POST|HEAD)$) {
return 405;
}
# 特定路径限制
location /api/ {
limit_except GET POST PUT DELETE {
deny all;
}
}
}
防止 SQL 注入和 XSS
http {
# 简单的 SQL 注入过滤
map $query_string $bad_query {
default 0;
~*(\"|'|<|>|;|--|union|select|insert|update|delete|drop|exec|script) 1;
}
server {
if ($bad_query) {
return 403;
}
# 或记录可疑请求
if ($bad_query) {
access_log /var/log/nginx/suspicious.log;
}
}
}
Mozilla SSL 配置推荐
Mozilla 提供三种配置级别:
# 现代配置(Modern)- 只支持 TLS 1.3
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
# 中等配置(Intermediate)- 推荐大多数场景
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;
# 旧配置(Old)- 兼容老旧客户端
ssl_protocols TLSv1 TLSv1.1 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:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA;
ssl_prefer_server_ciphers on;
推荐使用 Mozilla SSL Configuration Generator 生成配置。
完整 HTTPS 站点配置模板
# /etc/nginx/conf.d/example.com.conf
# HTTP 跳转 HTTPS
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# ACME challenge(Let's Encrypt 续期用)
location /.well-known/acme-challenge/ {
root /var/www/letsencrypt;
}
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 主站
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# === SSL 证书 ===
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.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:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# === SSL 会话 ===
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# === OCSP Stapling ===
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# === 安全响应头 ===
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" 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;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# === 站点配置 ===
root /var/www/example.com;
index index.html index.htm;
charset utf-8;
# 日志
access_log /var/log/nginx/example.com.access.log main;
error_log /var/log/nginx/example.com.error.log;
# 默认路由
location / {
try_files $uri $uri/ /index.html;
}
# 静态资源
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# 安全限制
location ~ /\. {
deny all;
}
# 错误页面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
}
总结
本章介绍了 Nginx HTTPS 配置与安全加固的全面内容:
- HTTPS 原理:TLS 握手过程、加密方式、数字证书
- 证书获取:Let's Encrypt 免费证书、自签名证书、商业证书
- HTTPS 配置:协议版本、加密套件、DH 参数
- 性能优化:Session 缓存、OCSP Stapling、HTTP/2
- 安全响应头:CSP、HSTS、X-Frame-Options 等
- 双向认证:mTLS 客户端证书验证
- 安全最佳实践:隐藏版本号、访问控制、请求过滤