HONGWEI's Blog

Django教程: 支持HTTPS访问及Nginx配置SSL证书

Django 111

什么是HTTPS?

简单来说:HTTPS = HTTP + SSL / TLS

也就是在HTTP(超文本传输协议)上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),即安全套接字层超文本传输协议,它是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。HTTPS 在HTTP 的基础下加入SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。

注意:HTTP协议默认使用的是80端口,而HTTPS协议默认使用的是443端口。

获取SSL证书

SSL证书,通常包括一张证书(.cert或.pem)和一个私有密钥文件(.key)。

SSL证书分很多类型,贵的都是高级别的HTTPS证书,比如EV证书。免费的HTTPS证书是低级别的证书,如DV证书,DV证书只验证域名所有权,且功能有限制,支持单个或者少数几个域名,所以免费。个人站长可以申请免费SSL证书来用,成本低,也能起到加密作用。

其实免费的SSL证书阿里云、腾讯云、Lets Encrypt、freessl等等都有,足够个人网站使用。以阿里云举例

在这里插入图片描述 购买证书 在这里插入图片描述

配置nginx

将获取到的证书和密钥上传到服务器的任何一个指定目录,如我的在下面是基本配置

server {
    listen 443 ssl;  # 端口
    server_name blog.zhwei.cn;  # 域名
    ssl_certificate   /etc/nginx/cert/fullchain.crt;  # 证书
    ssl_certificate_key  /etc/nginx/cert/privkey.key;  # 密钥
}

Django部署时以Nginx做反向代理和静态文件服务器,这里以基于 Docker 的 Django 容器化部署教程为例进行配置
nginx配置

server {
    listen 443 ssl;
    server_name blog.zhwei.cn;  # 域名

    ssl on;
    ssl_certificate   /etc/nginx/cert/fullchain.crt;
    ssl_certificate_key  /etc/nginx/cert/privkey.key;
    ssl_ciphers                 TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+ECDSA+AES128:EECDH+aRSA+AES128:RSA+AES128:EECDH+ECDSA+AES256:EECDH+aRSA+AES256:RSA+AES256:EECDH+ECDSA+3DES:EECDH+aRSA+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers    on;
    ssl_protocols                TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_session_cache            shared:SSL:50m;
    ssl_session_timeout          1d;
    ssl_session_tickets          on;

    # 配置docker-compose.yml中挂载的 static 
    location /static/ {
        autoindex on;
        alias /opt/hw-blog/static/;
    }

    # 配置docker-compose.yml中挂载的 media
    location /media/ {
        autoindex on;
        alias /opt/hw-blog/media/;

    }

    # 拦截所有请求 服务转发 端口需要一致
    location / {
        proxy_pass http://website:7000;
        proxy_set_header Host $http_host; #header添加请求host信息
        proxy_set_header X-Forwarded-Proto $scheme
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 增加代理记录
    }
}

如果想http请求永久地重定向至https只需加上下面的内容

server {
    listen       80;
    server_name  blog.zhwei.cn; # 域名
    return 301 https://$host$request_uri;
} 


docker-compose.yml需要把证书目录映射

 nginx:
    image: nginx:latest
    container_name: hw_nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./django/static:/opt/hw-blog/static
      - ./django/media:/opt/hw-blog/media
      - ./nginx:/etc/nginx/conf.d
      - /opt/ssl/blog.zhwei.cn:/etc/nginx/cert  # 证书目录
    depends_on:
      - website
    networks:
      - django_network

配置Django支持https

Django网站和用户数据提供更高级别的保护,需要在settings.py新增如下安全配置

# SECURITY安全设置 - 支持http时建议开启
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")   # 推荐
SECURE_SSL_REDIRECT = True # 将所有非SSL请求永久重定向到SSL
SESSION_COOKIE_SECURE = True # 仅通过https传输cookie
CSRF_COOKIE_SECURE = True # 仅通过https传输cookie
SECURE_HSTS_INCLUDE_SUBDOMAINS = True # 严格要求使用https协议传输
SECURE_HSTS_PRELOAD = True # HSTS为
SECURE_HSTS_SECONDS = 60
SECURE_CONTENT_TYPE_NOSNIFF = True # 防止浏览器猜测资产的内容类型

还有一种方法,但是我没有尝试

DjangoSECURE_SSL_REDIRECT = True也可实现80端口的http请求永久地重定向至https, 与Nginx的301重定向设置选其一即可。Django以上的几个安全设置均依赖下面这个SecurityMiddleware中间件。

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
]

这时候如果在模板中使用{{ request.build_absolute_uri }}即可自动识别https


本文链接: https://blog.zhwei.cn/article/django-nginx-https-ssl
版权声明: 本博客所有文章除特别声明外,均遵循 CC 4.0 BY-NC-SA 版权协议。转载请附上原文链接!