I have a web app hosted on Heroku, which uses Django, with the domain (say) example.com. I wanted to make all incoming http://example.com requests redirect to https://example.com.
I set up SecurityMiddleware in Django and set SECURE_SSL_REDIRECT to be True, which "redirects all non-HTTPS requests to HTTPS". This seems to work.
Heroku serves as a proxy to my Django app. So when the Heroku load-balancer gets an HTTPS request, it (probably) routes to my web app using a non-HTTPS connection. Which freaks out my app, and it redirects it to HTTPS again, setting off a redirect loop.
The way to solve this seems to be to set SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') as a setting in Django. This tells my app: if the proxy sends the header 'HTTP_X_FORWARDED_PROTO', and if its value is 'https', then trust the connection. I tried this, and it works.
However, I'm warned by the Django docs that I should make sure that my proxy strips incoming 'X_FORWARDED_PROTO' headers, which makes sense: if a malicious agent sends this header over a http connection with an https value my web app will be fooled.
How do I check if Heroku strips the X_FORWARDED_PROTO header from incoming requests?
Like documented in Heroku headers, you'll find:
X-Forwarded-Proto: the originating protocol of the HTTP request (example: https)
This implies that the header will be set by Heroku regardless of the original request header. This can easily be tested by setting the given header with a request manually like mentioned in a comment:
curl -I -H 'X-Forwarded-Proto: https' http://yourapp.heroku.com
This will result in X-Forwarded-Proto being set to http for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With