ssl - 无法激活与 Django 和 Nginx 的 HTTPS 链接

标签 ssl nginx https django-rest-framework

我有一个在安全的 Nginx 服务器上运行的 Django 休息框架应用程序。 当我在 DRF api 上导航时,导航栏中的协议(protocol)很好地重定向到 https。 我的问题是所有生成的 url 都在 http 而不是 https 中。 我在代码中看到,不同的 url 是用这种方法构建的:

def build_absolute_uri(self, location=None):
        """
        Build an absolute URI from the location and the variables available in
        this request. If no ``location`` is specified, bulid the absolute URI
        using request.get_full_path(). If the location is absolute, convert it
        to an RFC 3987 compliant URI and return it. If location is relative or
        is scheme-relative (i.e., ``//example.com/``), urljoin() it to a base
        URL constructed from the request variables.
        """
        if location is None:
            # Make it an absolute url (but schemeless and domainless) for the
            # edge case that the path starts with '//'.
            location = '//%s' % self.get_full_path()
        bits = urlsplit(location)
        if not (bits.scheme and bits.netloc):
            current_uri = '{scheme}://{host}{path}'.format(scheme=self.scheme,
                                                           host=self.get_host(),
                                                           path=self.path)
            # Join the constructed URL with the provided location, which will
            # allow the provided ``location`` to apply query strings to the
            # base path as well as override the host, if it begins with //
            location = urljoin(current_uri, location)
        return iri_to_uri(location)

在我的例子中,这个方法总是返回不安全的 url(HTTP 而不是 HTTPS)。 我已经像这篇文章中描述的那样编辑了我的设置: https://security.stackexchange.com/questions/8964/trying-to-make-a-django-based-site-use-https-only-not-sure-if-its-secure 但是生成的 url 仍然是 HTTP。 这是我的 Nginx 配置:

server {
        listen 80;
        listen [::]:80;

        server_name backend.domaine.na.me www.backend.domaine.na.me server_ip:8800;

        return 301 https://$server_name$request_uri;
}

server {
        # SSL configuration

        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        include snippets/ssl-backend.domaine.na.me.conf;
        include snippets/ssl-params.conf;

        location / {
                proxy_pass http://server_ip:8800/;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto https;
                proxy_set_header Host $http_host;
                proxy_redirect off;
        }
}


server {
        listen 8800;
        server_name server_ip;
        location = /favicon.ico { access_log off; log_not_found off; }

        location /static/ {
                root /projects/my_django_app;
        }

        location /media/ {
                root /projects/my_django_app;
        }

        location / {
                include proxy_params;
                proxy_pass http://unix:/projects/my_django_app.sock;
        }

        location ~ /.well-known {
                allow all;
        }
}

还有我的 django 配置:

wsgi.py中:

os.environ['HTTPS'] = "on"
os.environ['wsgi.url_scheme'] = "https"

settings.py(注意:前两行我都试过了):

#SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_PROXY_SSL_HEADER = ('HTTP_X_SCHEME', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

我真的需要解决这个问题,因为我的 DRF api 返回了一些必须使用 HTTPS 的图像 URL,否则该站点不能被认为是 100% 安全的。

我的配置有什么问题?我是否遗漏了一些选项?

最佳答案

不需要间接寻址;您可以合并 SSL block 和 :8800 block 中的设置以提供如下内容:

server {
        listen 80;
        listen [::]:80;

        server_name backend.domaine.na.me www.backend.domaine.na.me;

        return 301 https://$server_name$request_uri;
}

server {
        # SSL configuration

        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        include snippets/ssl-backend.domaine.na.me.conf;
        include snippets/ssl-params.conf;

        location = /favicon.ico { access_log off; log_not_found off; }

        location /static/ {
                root /projects/my_django_app;
        }

        location /media/ {
                root /projects/my_django_app;
        }

        location ~ /.well-known {
                allow all;
        }

        location / {
                proxy_pass http://unix:/projects/my_django_app.sock;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto https;
                proxy_set_header Host $http_host;
                proxy_redirect off;
        }
}

然后,设置 SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') 它应该可以工作。

我找不到任何关于 include proxy_params 的信息,我怀疑您在第一个代理 block 中设置的 header 根本没有转发到 Django 应用程序。

关于ssl - 无法激活与 Django 和 Nginx 的 HTTPS 链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43189444/

相关文章:

ssl - Kubernetes Ingress TLS 不是使用 headless 服务创建的

c# - WebClient 能够执行多个请求

android - 如何代理对 api.twitter.com 的请求,包括 SSL 证书?

java - SunMSCAPI 不返回证书

ssl - Nginx错误日志中的 "SSL_CTX_use_PrivateKey_file" "problems getting password error"表示什么?

javascript - 使用 JavaScript 从安全的 https 弹出窗口重新加载 http 父窗口

perl - 我如何确定连接在 mod_perl 中使用的是哪个 SSL 客户端证书?

nginx - 如何在jwilder/nginx-proxy下将no-www重定向到www?

nginx - Cloudflare CDN和NGINX之间的区别

https - 设置 Identity Server 4 反向代理