Does django csrf token must be unique on every request?
Asked Answered
C

1

9

I have a question about Django CsrfViewMiddleware mechanism. I know, that Django:

  1. Set new csrftoken cookie on every request.
  2. Check, than X-CSRFToken header value (or hidden input "csrfmiddlewaretoken") must be equals to csrftoken cookie.

But Django doesn't check whether token has been used already (example from CsrfViewMiddleware):

if not constant_time_compare(request_csrf_token, csrf_token):
            return self._reject(request, REASON_BAD_TOKEN)

So I can POST multiple requests with the same token (I tested it on my server).

Is it standart behavior, or I have incorrect Django setup? Thanks.

Capsule answered 26/8, 2014 at 13:50 Comment(1)
Standard. The token is not consumed, but only refreshed at every login.Bulbar
S
2

CSRF tokens are not consumed.

To elaborate on Germano's comment, the reasoning behind it is simple:

Multiple browser windows / tabs and REST

Essentially, Django would have to create (and persist, and, in distributed 'cloud' deployment, synchronize) new CSRF tokens for every single page that has been rendered in the past. Essentially, this would easily lead to Denial of Service attacks, where you cannot assume any sensible expiration for the CSRFs.

Stroganoff answered 27/8, 2014 at 12:28 Comment(9)
So the solution is to write own Middleware, which will check CSRF token expiration datetime?Capsule
Not quite - you basically don't want to store many different CSRF's for different views or pages - otherwise, you create a mechanism where you can easily overload the database with awful lot of CSRF's.Stroganoff
I don't get the problem. Why do you want the token to expire earlier?Bulbar
The purpose is to disable post html form twice. I have javascript checks on page, but i wanted also to add checks on server.Capsule
@Capsule Are you talking about this? en.wikipedia.org/wiki/Post/Redirect/GetBulbar
@Germano, no. For example, in the online shop user makes order. When he clicks button 'Make order', POST request is sent to server. If user clicks twice, two POST request will be sent to server. I wanted to prevent this.Capsule
@Capsule If I understand, you want to prevent a double form submission when a user double click a button. If that's the case, you can solve it on the client side by disabling the submit form after the first click. Something like <form [...] onsubmit="submit_button.disabled=true; return true;">Bulbar
@Germano, yes, thanks. But what if user switched off the Javascript? How to make same checks on the server side?Capsule
The usual solution would be a one time value saved server side, and checked on submission. I see why you might think to use the csrf token for this, but as others point out, it is persistent so not suitable. Banking apps would set a unique number on the server when delivering the page with the form, then when the submission comes back, save that number as submitted. A double post using the same number again would be rejected.Objective

© 2022 - 2024 — McMap. All rights reserved.