Opened 8 years ago

Closed 8 years ago

#24696 closed Cleanup/optimization (fixed)

CSRF middleware wastefully calculates new tokens that are never used .

Reported by: Jay Cox Owned by: nobody
Component: CSRF Version: 1.8
Severity: Normal Keywords: CSRF performance
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


When a client requests a page from a site running the csrf middleware and does not send a csrf cookie - a new CSRF token is generated even if the page does not use the token. This unnecessary token generation can add about 40% to the response time for simple requests.

I have created a pull request with a solution that only generates a csrf token when it is going to be used.

Git hub pull request:

Change History (5)

comment:1 Changed 8 years ago by Moritz Sichert

Do you have some evidence that the response time gets sped up this much?

As I see it, django.template.context_processors.csrf sets the token as a SimpleLazyObject so it should already be lazy.

comment:2 Changed 8 years ago by Jay Cox

It is not the context processor causing the computation. It is the csrf middleware (CsrfViewMiddleware .process_view) which computes a new token automatically if there was no csrf cookie sent with the request.

I benchmarked a simple view using siege with the csrf middleware active and again with my patch applied to come up with the 40% number.

The view I benchmarked:

def json(request):
  response = {
    "message": "Hello, World!"
  return HttpResponse(uj_dumps(response), content_type="application/json")

I also ran it under the python cprofiler before patching while exercising the above view and got these results:

Trimmed for relavant section
 ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1418    0.010    0.000    4.970    0.004
     1418    0.007    0.000    4.882    0.003
     1418    0.018    0.000    4.775    0.003
     1418    0.011    0.000    4.752    0.003
     1418    0.013    0.000    4.452    0.003
     1418    0.028    0.000    4.374    0.003
     1417    0.011    0.000    3.775    0.003
     1417    0.047    0.000    2.800    0.002
     1417    0.076    0.000    2.311    0.002
     1417    0.023    0.000    1.123    0.001
18450/18444    0.094    0.000    1.096    0.000 {method 'join' of 'unicode' objects}
     1417    0.005    0.000    1.083    0.001
     1417    0.007    0.000    1.078    0.001
    46761    0.128    0.000    1.002    0.000<genexpr>)

In this example no csrf token is ever sent back to the requesting client but it is spending a fair amount of time calculating it on every request.

comment:3 Changed 8 years ago by Tim Graham

Has patch: set
Triage Stage: UnreviewedAccepted

comment:4 Changed 8 years ago by Tim Graham

Triage Stage: AcceptedReady for checkin

comment:5 Changed 8 years ago by Tim Graham <timograham@…>

Resolution: fixed
Status: newclosed

In eef95ea:

Fixed #24696 -- Made CSRF_COOKIE computation lazy.

Only compute the CSRF_COOKIE when it is actually used. This is a
significant speedup for clients not using cookies.

Changed result of the “test_token_node_no_csrf_cookie” test: It gets
a valid CSRF token now which seems like the correct behavior.

Changed auth_tests.test_views.LoginTest.test_login_csrf_rotate to
use get_token() to trigger CSRF cookie inclusion instead of changing
request.METACSRF_COOKIE_USED? directly.

Note: See TracTickets for help on using tickets.
Back to Top