Do we need an easier toggle for `request.is_secure()` to be True?

Hi all.

HttpRequest.is_secure(): Returns True if the request is secure; that is, if it was made with HTTPS.

Django isn’t magic here: it goes on a couple of clues as to what to answer there:

Getting this right has always been a bit of a pain.

Since Django 4.0 though, CSRF protection uses this to check the Origin header, and there are lots of posts of people tripping up on it.

But there are legion. A search for CSRF trusted origins has the same issue again and again and again.

I think :thinking: the main issue is that SECURE_PROXY_SSL_HEADER is hard to get right, and varies between environments significantly.

But, in contrast to the old days, HTTPS is the norm now. Having a really fiddly setting, dependent on equally fiddly settings in my hosting environment, just to get the default to work seems (maybe) an undue burden now.

Should we add some toggle — Grrr, a setting? :grimacing: — to more easily say, This project will always be served with HTTPS, and have HttpRequest.is_secure() always defer to that?

This is security sensitive, so we must be careful not just to jump on Yes. :rotating_light:

While I understand that people are having an issue with this, it is worth noting that the combination of SECURE_PROXY_SSL_HEADER and wsgi.url_scheme always fixes this. I do give you that it requires an understanding of how http headers are used to communicate between proxies and the wsgi server, but that is not the worst thing for something security sensitive.

Your TIL is interesting for multiple reasons: First off, it obviously fixes the problem for you by tying directly into the WSGI env variables. It also has the upside that for instance Gunicorn can use this information for logging (I am doing similar things with the remote ip, which Gunicorn would otherwise only see as the proxy in front of it). So while your approach does have the upside of making this work with everything being able to work of WSGI env variables (be that gunicorn or for instance a sentry and other tools that tap into that info) it also has the downside of being code and hard to adjust to different environments if it extends to more than just HTTPS handling (though I agree that is not your goal here).

So all in all I am somewhere between +0 and -0 personally – I can see this being a pain for people, but I think that the current code works well enough for this. On the other hand (and I know how to configure this stuff by heart) I am also often in the situation where I know that I have a proxy in the same network namespace and the only way to talk to my app is secured via HTTPS, and I really don’t want to waste time remembering which header my proxy uses this time.

This whole thing also reminds me a bit of https://groups.google.com/g/django-developers/c/YzRj7OXpLkk (thanks to @sarahboyce for putting that up – took me a while to find it since I was searching for it in the forum :D). While a BASE_URL wouldn’t tell you whether you are actually on HTTP or HTTPS (it solely is ment to provide a “default”) it also taps into two things that are kinda “hard” to get. One is the domain you are currently on (depending on the proxy this might or might not be the normal Host header but an X-Forwarded-Host header) and the other is the subpath that Django is mounted on.

Hope that helps :slight_smile:

1 Like