My app's web site is built with Django. I use the built-in CSRF tools. (I should emphasize that my site is strictly HTTPS.)
In theory, no normal user will ever fail CSRF checks. In practice, tons of people have complained that they see Django's (very confusing) CSRF error page when they try to sign up for my service.
This was surprising to me; I thought we were _way_ past this point. Digging into it, I've learned that tons of people use extensions that muck about with cookies in ways that break Django's CSRF feature. I don't really know a way around it.
Yeah this is something I run into often as I don't accept cookies from sites by default and don't send Referer header (both are required for django's CSRF middleware if over https). This is a good read if you are interested in the rational behind these decisions -> https://code.djangoproject.com/wiki/CsrfProtection
As far as a solution for your users, I'd just let them know that you require cookies to login (obviously) and if you are posting over https make sure they have the Referer header which can be forged to just be the domain and not the entire URL if they prefer. I use https://addons.mozilla.org/en-US/firefox/addon/refcontrol/ set to forge for django sites.
Yeah, there are plenty of reasons to do what you're doing that seem fair to me. But at the same time, through no fault of yours, your requests are indistinguishable from potentially malicious ones. The whole thing is a mess, effectively a band-aid on top of deeper issues with HTTP's statelessness.
If I'm blocking cookies/referer by default then the onus is upon me to enable them for sites that require them for stuff like this. I wouldn't worry about users who have this issue. Maybe customize django's CSRF failure page to say they need to enable both to use your service and call it a day.
I agree in principle. And I have built a custom CSRF page to help my potential customers out.
In practice, lots of my potential users don't even understand that their AdBlock/whatever extensions are mucking about with Cookies in ways that break things. It's a tough sell to tell someone who is thinking about trying your service: "sorry, I don't work with your browser the way it is" when so much of the rest of the world is either HTTP, not HTTPS, or simply has decided to punt on CSRF or be much more selective about it. It looks to them like _I'm_ the one that's broken.
Humm.. I'm thinking you could write a middleware that checks for Referer over https and if not set, go ahead and set it to https://yourdomain.com That would allow you to continue to use CSRF middleware for the nonce check (just make sure yours is before theirs).
In order to exploit this an attacker would need to be MITM on the network or on a subdomain by setting a wildcard cookie. The site would still keep the nonce check. I don't see any way around this without poking a tiny hole in the CSRF protection. Guess you gotta weigh the cost/benefit.
Update: I noticed that later in the thread you mention that you already provide a custom error page. I'll leave this for others who might not be familiar with custom CSRF error pages.
I am not familair with Django's CSRF tools, but you could write your own that didn't depend on cookies. Init a js var with a random token in the html somewhere, then require that the browser includes it with any state changing actions.
AFAICT django requires the token as a form parameter, which would be what you suggest doing with javascript.
The issue is the "require that the browser includes it", as the information on the token must be available to the server too, and django apparently puts that in a cookie (rails does too, if the session is stored in the cookie).
So I believe you have suggested a fix for the bit that works already, but not for grandparent's actual problem :)
In theory, no normal user will ever fail CSRF checks. In practice, tons of people have complained that they see Django's (very confusing) CSRF error page when they try to sign up for my service.
This was surprising to me; I thought we were _way_ past this point. Digging into it, I've learned that tons of people use extensions that muck about with cookies in ways that break Django's CSRF feature. I don't really know a way around it.
How common is this, in your experience?