Skip to content

深入理解 Nginx HTTPS 配置与安全加固

本文是 Nginx 实操专栏的第四篇,我们将深入探讨 HTTPS 配置、SSL/TLS 优化以及安全加固措施,帮助你构建更加安全可靠的 Web 服务。

引言

随着网络安全意识的不断提高,HTTPS 已经成为现代网站的标准配置。Nginx 作为流行的 Web 服务器和反向代理,提供了强大的 SSL/TLS 支持。在本文中,我们将详细介绍如何在 Nginx 中配置 HTTPS,优化 SSL/TLS 性能,并实施各种安全加固措施。

SSL/TLS 基础知识

在深入配置之前,我们需要了解一些 SSL/TLS 的基础知识。

什么是 SSL/TLS?

SSL(Secure Sockets Layer)和它的继任者 TLS(Transport Layer Security)是用于在网络上提供通信安全的加密协议。它们通过以下方式保护数据:

  1. 加密传输数据 - 防止窃听
  2. 验证服务器身份 - 防止中间人攻击
  3. 保证数据完整性 - 防止篡改

证书类型

  1. 域名验证证书(DV) - 验证域名所有权
  2. 组织验证证书(OV) - 验证域名所有权和组织信息
  3. 扩展验证证书(EV) - 最严格的验证,显示绿色地址栏

基本 HTTPS 配置

获取 SSL 证书

首先,你需要获取 SSL 证书。有几种方式可以获得证书:

  1. 购买商业证书 - 从受信任的证书颁发机构购买
  2. Let's Encrypt - 免费的自动化证书颁发机构
  3. 自签名证书 - 仅用于测试环境

使用 Let's Encrypt 获取证书的示例:

bash
# 安装 Certbot
sudo apt install certbot python3-certbot-nginx

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

基本 HTTPS 服务器配置

nginx
server {
    # 监听 HTTPS 端口
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    
    server_name example.com www.example.com;
    
    # SSL 证书文件路径
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/private.key;
    
    # 网站根目录
    root /var/www/example.com;
    index index.html;
    
    # 其他配置...
}

HTTP 重定向到 HTTPS

为了确保所有流量都通过 HTTPS 传输,我们需要将 HTTP 请求重定向到 HTTPS:

nginx
# HTTP 服务器块 - 重定向到 HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    
    # 永久重定向到 HTTPS
    return 301 https://$server_name$request_uri;
}

SSL/TLS 优化配置

协议版本和加密套件

为了平衡安全性和兼容性,我们需要选择合适的协议版本和加密套件:

nginx
server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/private.key;
    
    # 支持的协议版本
    ssl_protocols TLSv1.2 TLSv1.3;
    
    # 加密套件
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
    
    # 优先使用服务器定义的加密套件
    ssl_prefer_server_ciphers off;
    
    # 启用会话复用
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # 启用 OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
}

Diffie-Hellman 参数

为了增强前向安全性,建议使用自定义的 Diffie-Hellman 参数:

bash
# 生成 DH 参数文件(可能需要较长时间)
openssl dhparam -out /etc/nginx/dhparam.pem 2048

然后在 Nginx 配置中引用:

nginx
ssl_dhparam /etc/nginx/dhparam.pem;

HTTP/2 支持

HTTP/2 提供了更好的性能,但只能在 HTTPS 下使用:

nginx
listen 443 ssl http2;

安全加固措施

安全头设置

通过设置适当的安全头,可以增强网站的安全性:

nginx
server {
    listen 443 ssl http2;
    server_name example.com;
    
    # 隐藏服务器版本信息
    server_tokens off;
    
    # 防止点击劫持
    add_header X-Frame-Options DENY;
    
    # 防止 MIME 类型嗅探
    add_header X-Content-Type-Options nosniff;
    
    # 启用 XSS 过滤
    add_header X-XSS-Protection "1; mode=block";
    
    # 强制 HTTPS(HSTS)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    # 内容安全策略
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'";
    
    # 引用策略
    add_header Referrer-Policy "strict-origin-when-cross-origin";
}

强制 HTTPS(HSTS)

HTTP Strict Transport Security (HSTS) 告诉浏览器只能通过 HTTPS 访问网站:

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

参数说明:

  • max-age - 指定时间内浏览器应只使用 HTTPS
  • includeSubDomains - 包括所有子域名
  • preload - 可选,表示希望加入浏览器预加载列表

防止协议降级攻击

通过设置适当的 TLS 配置防止协议降级攻击:

nginx
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

性能优化

SSL 会话复用

启用 SSL 会话复用可以减少握手开销:

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

# 票据会话复用(TLS 1.3)
ssl_session_tickets on;

OCSP Stapling

OCSP Stapling 可以提高证书验证速度:

nginx
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

内容压缩

虽然启用了 HTTP/2,但仍可以使用 gzip 压缩:

nginx
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

高级配置示例

多域名 SNI 支持

Server Name Indication (SNI) 允许在同一个 IP 地址上托管多个 HTTPS 网站:

nginx
# 网站 A
server {
    listen 443 ssl http2;
    server_name sitea.com;
    
    ssl_certificate /path/to/sitea.crt;
    ssl_certificate_key /path/to/sitea.key;
    
    root /var/www/sitea;
}

# 网站 B
server {
    listen 443 ssl http2;
    server_name siteb.com;
    
    ssl_certificate /path/to/siteb.crt;
    ssl_certificate_key /path/to/siteb.key;
    
    root /var/www/siteb;
}

客户端证书认证

对于需要更高安全性的应用,可以要求客户端证书:

nginx
server {
    listen 443 ssl;
    server_name secure.example.com;
    
    ssl_certificate /path/to/server.crt;
    ssl_certificate_key /path/to/server.key;
    
    # 要求客户端证书
    ssl_client_certificate /path/to/ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;
    
    location / {
        # 可以通过变量访问客户端证书信息
        add_header X-Client-CN $ssl_client_s_dn;
    }
}

通配符证书配置

使用通配符证书可以简化多子域名的配置:

nginx
server {
    listen 443 ssl http2;
    server_name *.example.com;
    
    ssl_certificate /path/to/wildcard.crt;
    ssl_certificate_key /path/to/wildcard.key;
    
    # 根据子域名提供不同内容
    location / {
        root /var/www/$host;
    }
}

监控和故障排除

SSL 错误日志

配置专门的 SSL 错误日志:

nginx
error_log /var/log/nginx/ssl_error.log debug;

测试 SSL 配置

使用在线工具测试 SSL 配置:

或者使用命令行工具:

bash
# 测试 SSL 连接
openssl s_client -connect example.com:443

# 检查证书信息
echo | openssl s_client -showcerts -connect example.com:443 2>/dev/null | openssl x509 -inform pem -noout -text

最佳实践总结

1. 证书管理

nginx
# 使用完整的证书链
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/private.key;

# 设置正确的文件权限
# chmod 600 /path/to/private.key
# chmod 644 /path/to/fullchain.pem

2. 安全配置

nginx
# 禁用不安全的协议和加密套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE+AESGCM:ECDHE+CHACHA20:!aNULL:!MD5:!DSS;

# 启用安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

3. 性能优化

nginx
# 启用会话复用
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

# 启用 OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;

自动化证书管理

使用 Certbot 自动续期

bash
# 测试续期
sudo certbot renew --dry-run

# 设置定时任务自动续期
# 添加到 crontab: 0 12 * * * /usr/bin/certbot renew --quiet

使用 acme.sh

bash
# 安装 acme.sh
curl https://get.acme.sh | sh

# 获取证书
acme.sh --issue -d example.com -w /var/www/html

# 安装证书到 Nginx
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.crt \
--reloadcmd "service nginx force-reload"

总结

通过合理的 HTTPS 配置和安全加固措施,我们可以显著提高网站的安全性。关键要点包括:

  1. 使用强加密协议和加密套件
  2. 正确配置证书和私钥
  3. 实施必要的安全头
  4. 启用性能优化功能
  5. 定期更新和续期证书

在下一章中,我们将探讨 Nginx 的负载均衡功能,帮助你构建高可用的 Web 应用架构。

要点回顾:

  1. HTTPS 配置需要有效的 SSL 证书
  2. 合理选择协议版本和加密套件以平衡安全性和兼容性
  3. 通过安全头增强网站安全性
  4. 启用性能优化功能如会话复用和 OCSP Stapling
  5. 定期管理和更新 SSL 证书