Opened 13 years ago

Closed 13 years ago

Last modified 13 years ago

#15518 closed New feature (fixed)

Separate CSRF checks to function

Reported by: Vlastimil Zíma Owned by: nobody
Component: Documentation Version: 1.2
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I have troubles with enabling CSRF check in some of my views because there is no function that would return True/False or raised an exception.

My situation is like this:
I have 2 views, one that is protected by CSRF and other one is not. Both views calls same rendering function which renders a form that leads to protected view.
Problem is when first request ends at unprotected view, I have no CSRF_COOKIE in request.META and csrf_token template tag did not rendered one, so rendering returns a form that will always return CSRF reject page.

Change History (8)

comment:1 by anonymous, 13 years ago

Resolution: invalid
Status: newclosed

It's not at all clear to me what you are asking for here. I suspect the root of the problem is a misunderstanding about how to use the CSRF protection, as it's perfectly possible to have some views that are CSRF protected and others that are not. I suggest you ask on #django IRC or post a more complete description of your code to django-users for help.

comment:2 by Luke Plant, 13 years ago

Resolution: invalid
Status: closedreopened

I understand the problem, and it is a valid ticket. There is already a solution - django.views.decorators.csrf.requires_csrf_token

However, this function is not documented, and therefore 'doesn't exist yet'. Once documented, I'll close this ticket.

comment:3 by Luke Plant, 13 years ago

Component: Core frameworkDocumentation
Triage Stage: UnreviewedAccepted

comment:4 by Vlastimil Zíma, 13 years ago

That is what I needed, but still there is no common way how to call CSRF check, if you want to do it manually.

Code for view with CSRF check not provided by middleware/decorator looks

from django.middleware.csrf import CsrfViewMiddleware, _get_new_csrf_key, _sanitize_token
from django.views.decorators.csrf import csrf_view_exempt

@csrf_view_exempt
def some_view(request):
    if (...some_conditions...):
        result = CsrfViewMiddleware().process_view(request, lambda: None, None, None)
        # if None is returned, than it is OK
        if result:
            # Store data back to session to prevent their loss
            return result
    return ...some other response...

We have view like this at endpoint for OpenID provider, but I do not like the way I have to call CSRF check.

comment:5 by Luke Plant, 13 years ago

An alternative way to do this is to split your view function into several views, or into a closures, and decorate with @csrf_protect:

@csrf_view_exempt
def some_view(request):

    # Any setup here, including vars that may be referenced in path_1 or path_2

    @requires_csrf_token
    def path_1(request):
        # ...

    @csrf_protect
    def path_2(request):
        # ...

    if (...some_condition...):
        return path_1(request)
    else:
        return path_2(request)

This seems like a reasonable solution to me, especially for something which is very definitely an edge case. If you have things that you need to do instead of immediately returning the 403 failure view, you can:

  • subclass CsrfViewMiddleware
  • override the _reject method
  • make your own version of csrf_protect using decorator_from_middleware.

This suggests we should make _reject public by calling it reject.

comment:6 by Łukasz Rekucki, 13 years ago

Severity: Normal
Type: New feature

comment:7 by Luke Plant, 13 years ago

Resolution: fixed
Status: reopenedclosed

In [16187]:

Fixed #15518 - documented requires_csrf_token

Thanks to vzima for a report that raised the issue.

comment:8 by Luke Plant, 13 years ago

In [16189]:

Documented the edge case of needing a view that is partly CSRF protected

Refs #15518.

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