0

Ive found that, using Django, CSRF tokens are required under scenarios (and should in general be):

For all incoming requests that are not using HTTP GET, HEAD, OPTIONS or TRACE, a CSRF cookie must be present, and the ‘csrfmiddlewaretoken’ field must be present and correct. If it isn’t, the user will get a 403 error.

I have found a great deal of documentation and examples relevant only when Django is rendering the page templates. In this case, your templates can use special {% csrf_token %} token to add a hidden field that, when submitted, allows the backend to effectively validate the form's origin.


So how does this generally work when Django is not rendering the pages? I can contrive a simple example where the frontend just uses React and the backend is strictly an API.

I've found other documentation that claim you can decorate your backend API methods with such things as @csrf_protect or @ensure_csrf_cookie. However, the decorators instruct Django to set CSRF tokens on backed replies for some view/API request.

Imagine a simple "login" type of scenario:

  1. React frontend renders Login page with form
  2. React frontend submits form with PUT to backend for auth

According to any docs or examples I can find, it would seem the React frontend would need to make some kind of preflight request to get the CSRF token. While no document says this explicitly, it seems necessary.

  1. React frontend renders Login page with form
  2. React frontend makes request to API endpoint for login (just to get CSRF token)
  3. Django backend replies to (2) with CSRF token set
  4. React frontend submits form (CSRF token set) with PUT to backend for auth

This question has a great answer but it seems to assume the CSRF token is already present in the document somehow. Where does it come from? In the simple login scenario I describe above there are no backend requests (that would have replied and added the csrftoken cookie) prior to the PUT form submission for auth.

Does this assume users are already authenticated and logged in?

sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • You set CSRF cookie on the initial render of your site (in your first case, #1, *React frontend renders Login page with form + CSRF token cookie"). The Login form HTML itself is a response, the request being browser asking to access your site. – Amadan Jul 15 '23 at 14:31
  • I.e. the cookie should already be present in the browser (unless you disabled CSRF protection) - just go ahead and try to use the `getCookie` function. – Amadan Jul 15 '23 at 14:39
  • @Amadan but Django does not render static files. Presently I was just using node's development server to serve the React frontend static files but will eventually serve with something like gunicorn. Either way, the frontend doesn't come from Django. – sherrellbc Jul 15 '23 at 14:39
  • Oh, I missed the fact that your first page is a static page... In that case, yes, your second scenario makes sense. You just need to make any request that will go through the middleware. The whole point of CSRF is to distinguish the user A and user B, which is impossible if both get the exact same response, so serving a static page (without involving any serverside code) is incompatible with the CSRF concept, unless I am missing something. – Amadan Jul 15 '23 at 14:41
  • Hm, so this is true even if I wanted to use the API via some cmdline tooling then? Like in some scenario where I have authenticated with the backend and gotten some API token. And at some point later I just want to use this token to PUT on some endpoint. You need to first do some dummy request to get CSRF token then do the PUT? Seems a bit clunky. – sherrellbc Jul 15 '23 at 14:44
  • Well the static page is just the _login_ page. Login is just a PUT auth. I wasnt expecting there to be a requirement that I need to first request something from the backend before authenticating my user. – sherrellbc Jul 15 '23 at 14:47
  • A scenario that CSRF token guards against is e.g. a link to a login form that contains an attacker's username and password, logging the attacker in on your computer, which might dupe the user into entering their own information into an attacker's account. With CSRF token requirement, with the login form being customised with a temporary token, this attack is not possible. For a very good discussion on CSRF and API, see [Should I use CSRF protection on Rest API endpoints?](https://security.stackexchange.com/questions/166724/should-i-use-csrf-protection-on-rest-api-endpoints) – Amadan Jul 15 '23 at 15:01
  • tl;dr: Either serve your index.html as a template, or make a GET request to get the token. There is no other way to do it, Django must be involved in order for CSRF protection to work. – Amadan Jul 15 '23 at 15:08
  • @Amadan but under some circumstances it seems like (at least for Django) the CSRF token is implemented with cookies and other times it is a hidden form element. Is the Form-based CSRF secret a Django-ism? Is it more commonly implement as a cookie? – sherrellbc Jul 15 '23 at 19:39

0 Answers0