Closed btbonval closed 10 years ago
Django CSRF rejects HTTP to HTTPS submissions: http://blog.vrplumber.com/b/2013/12/13/django-csrf-explicitly-doesnt-trust-http-when-submitting-https/
In this case we are sending HTTPS to HTTPS, but Django might not see it that way because nginx is handling the HTTPS.
myth confirmed. trapped CSRF failure.
> /home/vagrant/karmaworld/karmaworld/utils/csrf.py(3)csrf_failure()->None
-> pdb.set_trace()
(Pdb) list
1 def csrf_failure(request, reason=""):
2 import pdb
3 -> pdb.set_trace()
[EOF]
(Pdb) request.is_ajax()
True
(Pdb) request.method
'POST'
(Pdb) reason
u'Referer checking failed - https://localhost:6659/ does not match https://127.0.0.1:8000/.'
There's that 127.0.0.1:8000
again. Django runs on 127.0.0.1:8000
but nginx is sitting in front of it. Surely Django can be told this (and has at least in two different places)...
http://philipm.at/2013/django-permissivecsrf.html
"(Referer checking is not done for HTTP requests because the presence of the Referer header is not reliable enough under HTTP.)" Would explain why this is a new problem using HTTPS.
no real fixes suggested. He advertises a module (django-permissivecsrf
) as a workaround with reduced security. He also recommends using entirely HTTPS on a site, but that wouldn't fix the current problem really.
Alright well I guess it's time to Read Django Source Code. Gather 'round, children!
lib/python2.7/site-packages/django/middleware/csrf.py
REASON_BAD_REFERER = "Referer checking failed - %s does not match %s."
...
referer = request.META.get('HTTP_REFERER')
...
# Note that request.get_host() includes the port.
good_referer = 'https://%s/' % request.get_host()
if not same_origin(referer, good_referer):
reason = REASON_BAD_REFERER % (referer, good_referer)
...
from django.utils.http import same_origin
lib/python2.7/site-packages/django/utils/http.py
def same_origin(url1, url2):
"""
Checks if two URLs are 'same-origin'
"""
p1, p2 = urllib_parse.urlparse(url1), urllib_parse.urlparse(url2)
return (p1.scheme, p1.hostname, p1.port) == (p2.scheme, p2.hostname, p2.port)
This should be easy enough to read off the request in the failed CSRF trap.
> /home/vagrant/karmaworld/karmaworld/utils/csrf.py(3)csrf_failure()->None
-> pdb.set_trace()
(Pdb) referer = request.META.get('HTTP_REFERER')
(Pdb) referer
'https://localhost:6659/'
(Pdb) good_referer = 'https://%s/' % request.get_host()
(Pdb) good_referer
'https://127.0.0.1:8000/'
Okay. Why does request.get_host()
think the things it thinks? nginx must not be passing something valuable along!
Beta's nginx has this, whereas the VM I hadn't added it:
proxy_set_header Host $host;
http://wiki.nginx.org/HttpCoreModule#.24host
$host
doesn't always contain a port, thus $http_host
appears to be the correct choice. Beta is fine because it uses standard ports.
Problem solved with proxy_set_header Host $http_host;
.
Will update README and Vagrant file. Ticket will be closed when this change is vetted with a whole bunch of others and pushed.
btbonval commented on Feb 7, has answer perfect for me.
Great!
On Wed, Oct 1, 2014 at 1:46 AM, Ibegoldex Team notifications@github.com wrote:
btbonval commented on Feb 7, has answer perfect for me.
— Reply to this email directly or view it on GitHub https://github.com/FinalsClub/karmaworld/issues/324#issuecomment-57421642 .
This appears to be causing problems for #320 and #323 on my system. Beta appears not to have this problem. Unclear where this failure comes from.
There is related discussion in these places: