Jak używać ochrony CSRF w Django

Aby skorzystać z ochrony CSRF w swoich widokach, wykonaj następujące kroki:

  1. CSRF middleware jest domyślnie włączone w ustawieniu MIDDLEWARE. Jeśli nadpisujesz to ustawienie, pamiętaj, że django.middleware.csrf.CsrfViewMiddleware' powinno pojawić się przed jakimkolwiek view middleware, które zakłada, że ataki CSRF zostały opanowane.

    Jeśli go wyłączyłeś, co nie jest zalecane, możesz użyć csrf_protect() na poszczególnych widokach, które chcesz chronić (zobacz poniżej).

  2. W dowolnym szablonie, który używa formularza POST, użyj tagu csrf_token wewnątrz elementu <form> jeśli formularz jest dla wewnętrznego adresu URL, np:

    <form method="post">{% csrf_token %}
    

    Nie należy tego robić w przypadku formularzy POST, które kierują do zewnętrznych adresów URL, ponieważ spowodowałoby to wyciek tokena CSRF, prowadząc do luki.

  3. W odpowiednich funkcjach widoku, upewnij się, że RequestContext jest używany do renderowania odpowiedzi, tak aby {% csrf_token %} działał poprawnie. Jeśli używasz funkcji render(), widoków generycznych, lub aplikacji contrib, jest już zawarta, ponieważ wszystkie one używają RequestContext.

Używanie ochrony CSRF z AJAX-em

Podczas gdy powyższa metoda może być użyta dla żądań AJAX POST, ma ona pewne niedogodności: musisz pamiętać, aby przekazać token CSRF jako dane POST z każdym żądaniem POST. Z tego powodu istnieje alternatywna metoda: na każdym XMLHttpRequest, ustaw niestandardowy nagłówek X-CSRFToken (określony przez ustawienie CSRF_HEADER_NAME) na wartość tokena CSRF. Jest to często łatwiejsze, ponieważ wiele frameworków JavaScript zapewnia haki, które umożliwiają ustawienie nagłówków na każdym żądaniu.

Najpierw musisz uzyskać token CSRF. Jak to zrobić, zależy od tego, czy ustawienia CSRF_USE_SESSIONS i CSRF_COOKIE_HTTPONLY są włączone.

Ustawienie tokena w żądaniu AJAX

Na koniec będziesz musiał ustawić nagłówek na swoim żądaniu AJAX. Korzystanie z API fetch():

const request = new Request(
    /* URL */,
    {
        method: 'POST',
        headers: {'X-CSRFToken': csrftoken},
        mode: 'same-origin' // Do not send CSRF token to another domain.
    }
);
fetch(request).then(function(response) {
    // ...
});

Używanie ochrony CSRF w szablonach Jinja2

Backend szablonów Django Jinja2 dodaje { csrf_input }} do kontekstu wszystkich szablonów, co jest odpowiednikiem {% csrf_token %} w języku szablonów Django. Na przykład:

<form method="post">{{ csrf_input }}

Użycie metody dekoratora

Zamiast dodawać CsrfViewMiddleware jako ogólną ochronę, możesz użyć dekoratora csrf_protect`(), który ma dokładnie taką samą funkcjonalność, na poszczególnych widokach, które potrzebują ochrony. Musi być używany zarówno na widokach, które wstawiają token CSRF do wyjścia, jak i na tych, które akceptują dane formularza POST. (Często są to te same funkcje widoku, ale nie zawsze).

Używanie dekoratora samego w sobie jest niezalecane, ponieważ jeśli zapomnisz go użyć, będziesz miał dziurę w zabezpieczeniach. Strategia „pasa i szelek” polegająca na używaniu obu jest w porządku i poniesie minimalny narzut.

Obsługa odrzuconych wniosków

Domyślnie, odpowiedź «403 Forbidden» jest wysyłana do użytkownika, jeśli przychodzące żądanie nie przejdzie kontroli przeprowadzonej przez CsrfViewMiddleware. Powinno to być widoczne tylko wtedy, gdy istnieje prawdziwe Cross Site Request Forgery, lub gdy z powodu błędu programistycznego, token CSRF nie został dołączony do formularza POST.

Strona błędu nie jest jednak zbyt przyjazna, więc możesz chcieć zapewnić własny widok do obsługi tego warunku. Aby to zrobić, ustaw CSRF_FAILURE_VIEW.

Niepowodzenia CSRF są logowane jako ostrzeżenia do :ref:`django.security.csrf ` logger.

Używanie ochrony CSRF z buforowaniem

Jeśli tag szablonu csrf_token jest użyty przez szablon (lub funkcja get_token jest wywołana w inny sposób), CsrfViewMiddleware doda ciasteczko i nagłówek Vary: Cookie do odpowiedzi. Oznacza to, że middleware będzie grał dobrze z cache middleware, jeśli jest używany zgodnie z instrukcją (UpdateCacheMiddleware idzie przed wszystkimi innymi middleware).

Jednakże, jeśli używasz dekoratorów cache na poszczególnych widokach, CSRF middleware nie będzie jeszcze w stanie ustawić nagłówka Vary lub CSRF cookie, a odpowiedź będzie buforowana bez żadnego z nich. W tym przypadku, na każdym widoku, który będzie wymagał wstawienia tokena CSRF powinieneś użyć najpierw dekoratora django.views.decorators.csrf.csrf_protect():

from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect


@cache_page(60 * 15)
@csrf_protect
def my_view(request): ...

Jeśli używasz widoków opartych na klasach, możesz odwołać się do Decorating widoków opartych na klasach.

Testowanie i ochrona CSRF

The CsrfViewMiddleware will usually be a big hindrance to testing view functions, due to the need for the CSRF token which must be sent with every POST request. For this reason, Django’s HTTP client for tests has been modified to set a flag on requests which relaxes the middleware and the csrf_protect decorator so that they no longer rejects requests. In every other respect (e.g. sending cookies etc.), they behave the same.

If, for some reason, you want the test client to perform CSRF checks, you can create an instance of the test client that enforces CSRF checks:

>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)

Edge cases

Certain views can have unusual requirements that mean they don’t fit the normal pattern envisaged here. A number of utilities can be useful in these situations. The scenarios they might be needed in are described in the following section.

Disabling CSRF protection for just a few views

Most views requires CSRF protection, but a few do not.

Solution: rather than disabling the middleware and applying csrf_protect to all the views that need it, enable the middleware and use csrf_exempt().

Setting the token when CsrfViewMiddleware.process_view() is not used

There are cases when CsrfViewMiddleware.process_view may not have run before your view is run - 404 and 500 handlers, for example - but you still need the CSRF token in a form.

Solution: use requires_csrf_token()

Including the CSRF token in an unprotected view

There may be some views that are unprotected and have been exempted by csrf_exempt, but still need to include the CSRF token.

Solution: use csrf_exempt() followed by requires_csrf_token(). (i.e. requires_csrf_token should be the innermost decorator).

Protecting a view for only one path

A view needs CSRF protection under one set of conditions only, and mustn’t have it for the rest of the time.

Solution: use csrf_exempt() for the whole view function, and csrf_protect() for the path within it that needs protection. Example:

from django.views.decorators.csrf import csrf_exempt, csrf_protect


@csrf_exempt
def my_view(request):
    @csrf_protect
    def protected_path(request):
        do_something()

    if some_condition():
        return protected_path(request)
    else:
        do_something_else()

Protecting a page that uses AJAX without an HTML form

A page makes a POST request via AJAX, and the page does not have an HTML form with a csrf_token that would cause the required CSRF cookie to be sent.

Solution: use ensure_csrf_cookie() on the view that sends the page.

CSRF protection in reusable applications

Because it is possible for the developer to turn off the CsrfViewMiddleware, all relevant views in contrib apps use the csrf_protect decorator to ensure the security of these applications against CSRF. It is recommended that the developers of other reusable apps that want the same guarantees also use the csrf_protect decorator on their views.

Back to Top