Opened 11 years ago
Closed 11 years ago
#21326 closed Bug (needsinfo)
Small bug fix for javascript example snippet in docs for CSRF in AJAX requests
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Documentation | Version: | 1.4 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | yes | UI/UX: | no |
Description
On updating my javascript AJAX CSRF token fix to match the current docs, I encountered a problem. If your browser does not yet have the CSRF cookie for your site and you did not include {% csrf_token %} somewhere in the template rendered on full page load, the following will result in csrftoken
being undefined:
var csrftoken = getCookie('csrftoken');
Or with jQuery cookie plugin:
var csrftoken = $.cookie('csrftoken');
The example javascript code simply references this csrftoken
variable, set on initial page load, in ajaxSetup's beforeSend method. When an AJAX form is brought in later, regardless of whether it includes the csrf cookie, the javascript code assumes it already checked for the cookie and got undefined
, and it results in a 403 error.
The fix is simply to move the cookie checking function into ajaxSetup's beforeSend method. A fully working example, using Jquery >= 1.5.1 and the $.cookie plugin:
function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } } });
or a variant without the cookie plugin (see getCookie() in docs):
var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { if (!csrftoken) { csrftoken = getCookie('csrftoken'); } xhr.setRequestHeader("X-CSRFToken", csrftoken)); } } });
I found I also had to use the ensure_csrf_cookie()
decorator on the view used for the AJAX request in order for the token cookie to actually be included, regardless of whether I put {% csrf_token %} in the AJAX form template. I'm not sure why that is the case, but the docs imply this might be the expected behavior:
Warning
If your view is not rendering a template containing the csrf_token template tag, Django might not set the CSRF token cookie. This is common in cases where forms are dynamically added to the page. To address this case, Django provides a view decorator which forces setting of the cookie: ensure_csrf_cookie().
This is probably more of a bug than an optimization, but since it's not really part of the Django code, I just labeled it as an optimization.
Change History (3)
comment:1 by , 11 years ago
Component: | contrib.csrf → Documentation |
---|---|
Type: | Cleanup/optimization → Bug |
comment:2 by , 11 years ago
It seems to me that your problem:
"If your browser does not yet have the CSRF cookie for your site and you did not include {% csrf_token %} somewhere in the template rendered on full page load, the following will result in csrftoken being undefined:"
is addressed by the warning you mention later:
"If your view is not rendering a template containing the csrf_token template tag, Django might not set the CSRF token cookie. This is common in cases where forms are dynamically added to the page. To address this case, Django provides a view decorator which forces setting of the cookie: ensure_csrf_cookie()."
Does including ensure_csrf_cookie()
on the first (non-AJAX) view not address the problem?
comment:3 by , 11 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Andrew, please reopen if you believe this is still an issue, thanks.
Re-labeled as Bug and set component to Documentation.