In particular, I'm writing a Django RESTful API to back an iOS application, and I keep running into Django's CSRF protections whenever I write methods to deal with POST requests.
My understanding is that cookies managed by iOS are not shared by applications, meaning that my session cookies are safe, and no other application can ride on them. Is this true? If so, can I just mark all my API functions as CSRF-exempt?
That's not the purpose of CSRF. CSRF is to prevent direct posting of data to your site. In other words, the client must actually post through an approved path, i.e. view the form page, fill it out, submit the data.
An API pretty much precludes CSRF, because its entire purpose is generally to allow 3rd-party entities to access and manipulate data on your site (the "cross-site" in CSRF). So, yes, I think as a rule any API view should be CSRF exempt. However, you should still follow best practices and protect every API-endpoint that actually makes a change with some form of authentication, such as OAuth.
CSRF attacks rely on cookies being implicitly sent with all requests to a particular domain. If your API endpoints do not allow cookie-based authentication, you should be good.
Even if you do use cookie-based authentication, your cookies are safe because iOS apps do not share cookies. However, unless you intentionally block web browsers by requiring an unusual user-agent header, another party could build a browser-based app that uses your API, and that app would be vulnerable to CSRF attacks if your API supports cookie-based authentication and doesn't apply CSRF protection.
They do apply if you're also using your API to support a website.
In this case you still need some form of CSRF protection to prevent someone embedding requests in other sites to have drive-by effects on an authenticated user's account.
Chrome seems to deny cross-origin POST requests by default (other browsers may not be so strict), but allows GET requests cross-origin so you must make sure any GET requests in your API don't have side-effects.
This currently accepted answer (May 2012) is mostly correct, except for when you are using session-based authentication. It's also worth mentioning the role of CORS.
The simple scenario is that you visit foo.com
and the website executes Javascript to make an AJAX-based DELETE request to api.com/users/123
and ends up deleting the user on your behalf. Now this isn't always possible because of CORS -- browsers will prevent foo.com
from making a request to api.com
unless api.com
explicitly whitelists foo.com
. This also assumes that you are using session-based authentication for your APIs as opposed to token-based authentication. In session-based authentication, any user who is logged in to api.com
can execute requests while they remain logged in. If you have token-based authentication (each request must be crafted with an HTTP Authorization
header containing the auth token) then you are safe. Session-based authentication implicitly sends the auth token via cookies.
A slightly worse scenario is if one of your trusted CORS domains becomes compromised--say you have a form which doesn't sanitise Javascript and a user manages to inject JS onto your site through that form. If you are using session-based authentication, then an authenticated user visiting the page will see the Javascript run and make an API request. This could be disastrous and a very real possibility if you are using session-based authentication for your API.
According to DRF documentation, APIs are vulnerable to CSRF attack as long as the server uses authenticated session (instead of asking every time password)
The solution is
- Ensure that the 'safe' HTTP operations, such as
GET
, HEAD
and
OPTIONS
cannot be used to alter any server-side state.
- Ensure that any 'unsafe' HTTP operations, such as
POST
, PUT
, PATCH
and DELETE
, always require a valid CSRF token.