Django @login_required dropping https

2019-04-21 20:56发布

I'm trying to test my Django app locally using SSL. I have a view with the @login_required decorator. So when I hit /locker, I get redirected to /locker/login?next=/locker. This works fine with http.

However, whenever I use https, the redirect somehow drops the secure connection, so I get something like https://cumulus.dev/locker -> http://cumulus.dev/locker/login?next=/locker

If I go directly to https://cumulus.dev/locker/login?next=locker the page opens fine over a secure connection. But once I enter the username and password, I go back to http://cumulus.dev/locker.

I'm using Nginx to handle the SSL, which then talks to runserver. My nginx config is

upstream app_server_djangoapp {
server localhost:8000 fail_timeout=0;
}

server {
listen 80;
server_name cumulus.dev;

access_log  /var/log/nginx/cumulus-dev-access.log;
error_log  /var/log/nginx/cumulus-dev-error.log info;

keepalive_timeout 5;

# path for static files
root /home/gaurav/www/Cumulus/cumulus_lightbox/static;

location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    if (!-f $request_filename) {
        proxy_pass http://app_server_djangoapp;
        break;
    }
}
}

server {
listen 443;
server_name cumulus.dev;

ssl on;
ssl_certificate /etc/ssl/cacert-cumulus.pem;
ssl_certificate_key /etc/ssl/privkey.pem;

access_log  /var/log/nginx/cumulus-dev-access.log;
error_log  /var/log/nginx/cumulus-dev-error.log info;

keepalive_timeout 5;

# path for static files
root /home/gaurav/www/Cumulus/cumulus_lightbox/static;

location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Ssl on;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    if (!-f $request_filename) {
        proxy_pass http://app_server_djangoapp;
        break;
    }
}
}

1条回答
\"骚年 ilove
2楼-- · 2019-04-21 21:38

Django is running on plain HTTP only behind the proxy, so it will always use that to construct absolute URLs (such as redirects), unless you configure it how to see that the proxied request was originally made over HTTPS.

As of Django 1.4, you can do this using the SECURE_PROXY_SSL_HEADER setting. When Django sees the configured header, it will treat the request as HTTPS instead of HTTP: request.is_secure() will return true, https:// URLs will be generated, and so on.

However, note the security warnings in the documentation: you must ensure that the proxy replaces or strips the trusted header from all incoming client requests, both HTTP and HTTPS. Your nginx configuration above does not do that with X-Forwarded-Ssl, making it spoofable.

A conventional solution to this is to set X-Forwarded-Protocol to http or https, as appropriate, in each of your proxy configurations. Then, you can configure Django to look for it using:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
查看更多
登录 后发表回答