The Python Oracle

Django + Caddy = CSRF protection issues

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Lost Civilization

--

Chapters
00:00 Django + Caddy = Csrf Protection Issues
01:51 Accepted Answer Score 11
03:33 Thank you

--

Full question
https://stackoverflow.com/questions/7258...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #django #docker #reverseproxy #caddy

#avk47



ACCEPTED ANSWER

Score 11


Finally found out what was happening.

I first wanted to know the exact HTTP request that was sent from caddy to django:

sudo tcpdump -i lo -A -n port 8088

This confirmed that:

  • the Origin and Referer headers were set properly
  • the csrftoken cookie was sent properly

Once that was known, I could dig in the code from django. Specifically, this function in the CSRF middleware.

In conclusion:

  1. Caddy forwards the http request to django unencrypted (so HTTP-non-S between caddy and django).
  2. Django considers that request non-secure
  3. The CSRF protection expects the Origin header sent by the browser to be http:// because the request is not secure. In my case, it is https:// because my browser is talking to Caddy over https
  4. Because the Origin header does not match what the CSRF middleware expects, the request is rejected

It's actually a simple fix.

Since we know that Caddy will always ignore X-Forwarded-Proto from the browser and sets it itself, we can add SECURE_PROXY_SSL_HEADER to the settings.py in django:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

And voilĂ !

Now I can also set these to true:

  • SECURE_SSL_REDIRECT
  • SESSION_COOKIE_SECURE
  • CSRF_COOKIE_SECURE

EDIT Here's the Caddyfile, as per requested:

service.mywebsite.com {
        reverse_proxy localhost:8088
}