Proposal: Make CSRF token validation for other HTTP Methods (PUT, PATCH, DELETE) The Same as POST

105 views
Skip to first unread message

Osaetin Daniel

unread,
May 6, 2017, 6:49:57 PM5/6/17
to Django developers (Contributions to Django itself)
I came across this issue, because i'm building a SPA with Vue and Django Rest Framework as the backend.

I'm using SessionAuthentication Which requires that the CSRF token must be sent along with the data for HTTP methods that Change State on the Server if not the request would be flagged as invalid, for POST requests it's okay to send the CSRF token as part of the payload

e.g

{'foo': 'bar', 'csrfmiddlewaretoken': '....token'}

But for other requests this doesn't work and you're required to set the token in the request header to whatever
settings.CSRF_HEADER_NAME
 
is set to (By default it's "HTTP_X_CSRFTOKEN"). (This is what Django Rest Framework currently does through the browse-able API)

So i want to make a proposal to Elevate other HTTP methods, so the CSRF token can be sent directly with the payload as "csrfmiddlewaretoken" like you'll normally do for a POST request. The fallback to "settings.CSRF_HEADER_NAME" would remain so old code that depends on that behaviour does not break. This seems more consistent to me and also allows Django support two ways of sending the CSRF token. (Either through the header or in the payload directly)


If this is a terrible Idea, I would like to know why POST requests are the only methods that allows the CSRF token to be sent along with the payload directly instead of setting the token in the Header.

Thanks. 



Tom Christie

unread,
May 7, 2017, 2:44:00 AM5/7/17
to Django developers (Contributions to Django itself)
> If this is a terrible Idea, I would like to know why POST requests are the only methods that allows the CSRF token to be sent along with the payload directly instead of setting the token in the Header.

That behaviour is because GET and POST are the only two methods supported by browsers for HTML form submission. In the case of standard HTML forms it's not possible to add extra headers, so the only way to include a CSRF token is to include it in the payload.

For any other method you'll necessarily be making an AJAX request (or some other programmatic interaction outside of a browser) in which case adding the CSRF token to the headers is possible, and preferable.

Reasons that you might not want to allow the CSRF token in the payload include:

* What do you do about non-form encoded payloads. Do you allow a CSRF token in JSON? What about JSON where the top level element isn't an object but is a list, or a primitive such as a number? What about other encoding such as YAML or XML?
* DELETE requests don't typically include request payloads. Clients may not handle payloads on DELETE and might coerce data to query parameters in that case. Servers and intermediaries might not rely payloads on DELETE requests to the application.

Another way around of expressing this is that we don't really want a CSRF token in the payload in any cases, it's just that the constraints of HTML forms in browsers means it's the only way we can do it there.

- T :)

Osaetin Daniel

unread,
May 7, 2017, 12:42:57 PM5/7/17
to Django developers (Contributions to Django itself)
Thanks, Tom Christie. Now i understand why.
Reply all
Reply to author
Forward
0 new messages