Django 生产环境如何配置 HTTPS 强制跳转防止数据泄露?

文章导读
生产环境最稳妥的做法是在反向代理(如 Nginx)层终止 SSL,再通过 HTTP 头告知 Django 当前是 HTTPS 请求,最后开启 Django 的安全设置强制跳转。
📋 目录
  1. Django 配置修改 (settings.py)
  2. Nginx 完整配置示例
  3. 防火墙与服务重启
  4. 验证是否生效
  5. 常见故障排查
A A

生产环境最稳妥的做法是在反向代理(如 Nginx)层终止 SSL,再通过 HTTP 头告知 Django 当前是 HTTPS 请求,最后开启 Django 的安全设置强制跳转。

先说结论:不要直接在 Django 内部处理证书,而是配合反向代理完成跳转,同时修正代理头配置避免重定向循环。

  • 先判断:确认架构是 Django 直连 HTTPS 还是前方有 Nginx/Apache 代理
  • 优先做:配置 ALLOWED_HOSTS、SECURE_SSL_REDIRECT 和 SECURE_PROXY_SSL_HEADER
  • 再验证:使用 curl 测试 HTTP 请求是否返回 301 跳转且无循环,检查是否出现 400 错误

Django 配置修改 (settings.py)

生产环境必须显式声明允许的域名,否则 Django 会拒绝所有请求返回 400 Bad Request。同时开启安全设置强制 HTTPS。

# settings.py
ALLOWED_HOSTS = ['your-domain.com', 'www.your-domain.com', '127.0.0.1']

# 强制 HTTPS 跳转
SECURE_SSL_REDIRECT = True
# 告知 Django 信任代理传来的 HTTPS 标识
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

# 防止 Cookie 通过 HTTP 泄露
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# 可选:生产环境建议开启,防止客户端 JS 读取 Cookie
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True

Nginx 完整配置示例

需要在 Nginx 中配置两个 server 块:一个监听 80 端口强制跳转 HTTPS,另一个监听 443 端口处理 SSL 并传递协议头。

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    # 强制跳转 HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name your-domain.com www.your-domain.com;

    # SSL 证书路径
    ssl_certificate /etc/nginx/ssl/your-domain.com.crt;
    ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;

    location / {
        proxy_pass http://127.0.0.1:8000; # 根据实际 Django 运行端口修改
        
        # 关键:传递协议头,防止 Django 无限重定向
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

防火墙与服务重启

配置完成后,需确保防火墙开放 80 和 443 端口,并重启服务使配置生效。

1. 开放防火墙端口(以 UFW 为例):

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

2. 检查配置语法并重启 Nginx:

Django 生产环境如何配置 HTTPS 强制跳转防止数据泄露?
sudo nginx -t
sudo systemctl restart nginx

3. 重启 Django 服务(根据实际部署方式):

# 示例:Gunicorn
sudo systemctl restart gunicorn
# 示例:uWSGI
sudo systemctl restart uwsgi

验证是否生效

使用 curl 命令分别测试 HTTP 和 HTTPS 请求,观察响应头和状态码。

1. 测试 HTTP 自动跳转:

curl -I http://your-domain.com

预期返回 301 Moved Permanently,且 Location 头以 https:// 开头。

2. 测试 HTTPS 正常访问:

curl -I https://your-domain.com

预期返回 200 OK,且不再出现跳转。

常见故障排查

  • 无限重定向循环:通常是 SECURE_PROXY_SSL_HEADER 未配置或 Nginx 未传递 X-Forwarded-Proto 头。Django 始终认为请求是 HTTP 而不断跳转。
  • 400 Bad Request:检查 ALLOWED_HOSTS 是否包含当前访问的域名。生产环境默认不允许空主机头。
  • 健康检查失败:负载均衡器的 HTTP 健康检查可能被 301 重定向干扰,需配置豁免路径或改用 HTTPS 检查。
  • HSTS 谨慎开启:SECURE_HSTS_SECONDS 设置后浏览器会强制记住 HTTPS,一旦证书出问题很难恢复,建议稳定运行后再开。