Så här använder du Djangos CSRF-skydd¶
Följ dessa steg för att dra nytta av CSRF-skydd i dina vyer:
CSRF-mellanvaran är aktiverad som standard i inställningen
MIDDLEWARE
. Om du åsidosätter den inställningen, kom ihåg att'django.middleware.csrf.CsrfViewMiddleware'
bör komma före alla view middleware som antar att CSRF-attacker har hanterats.Om du inaktiverar det, vilket inte rekommenderas, kan du använda
csrf_protect()
på särskilda vyer som du vill skydda (se nedan).I alla mallar som använder ett POST-formulär ska du använda taggen
csrf_token
inuti elementet<form>
om formuläret är för en intern URL, t.ex:<form method="post">{% csrf_token %}
Detta bör inte göras för POST-formulär som riktar sig till externa webbadresser, eftersom det skulle leda till att CSRF-token läcker ut, vilket leder till en sårbarhet.
I motsvarande vyfunktioner ska du se till att
RequestContext
används för att rendera svaret så att{% csrf_token %}
fungerar korrekt. Om du använderrender()
-funktionen, generiska vyer eller Contrib-appar, är du redan täckt eftersom dessa alla använderRequestContext
.
Använda CSRF-skydd med AJAX¶
Även om ovanstående metod kan användas för AJAX POST-begäranden har den vissa nackdelar: du måste komma ihåg att skicka CSRF-token som POST-data vid varje POST-begäran. Av denna anledning finns det en alternativ metod: på varje XMLHttpRequest, ställ in en anpassad X-CSRFToken
header (som anges av inställningen CSRF_HEADER_NAME
) till värdet av CSRF-token. Detta är ofta enklare eftersom många JavaScript-ramverk tillhandahåller krokar som gör det möjligt att ställa in rubriker vid varje begäran.
Först måste du hämta CSRF-token. Hur du gör det beror på om inställningarna CSRF_USE_SESSIONS
och CSRF_COOKIE_HTTPONLY
är aktiverade eller inte.
Ställa in token på AJAX-begäran¶
Slutligen måste du ställa in rubriken på din AJAX-begäran. Använda API:et 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) {
// ...
});
Använda CSRF-skydd i Jinja2-mallar¶
Djangos Jinja2
mallbackend lägger till {{ csrf_input }}
i kontexten för alla mallar, vilket motsvarar {% csrf_token %}
i Djangos mallspråk. Till exempel:
<form method="post">{{ csrf_input }}
Använda dekorationsmetoden¶
I stället för att lägga till CsrfViewMiddleware
som ett allmänt skydd kan du använda csrf_protect()
-dekoratorn, som har exakt samma funktionalitet, på särskilda vyer som behöver skyddet. Den måste användas både på vyer som infogar CSRF-token i utdata och på de som accepterar POST-formulärdata. (Dessa är ofta samma vyfunktion, men inte alltid).
Det är inte att rekommendera att använda dekoratorn ensam, eftersom det finns ett säkerhetshål om man glömmer att använda den. Strategin med att använda båda är bra och medför minimalt med overhead.
Hantering av avvisade förfrågningar¶
Som standard skickas ett ”403 Forbidden”-svar till användaren om en inkommande begäran inte klarar de kontroller som utförs av CsrfViewMiddleware
. Detta bör vanligtvis bara ses när det finns en äkta Cross Site Request Forgery, eller när CSRF-token på grund av ett programmeringsfel inte har inkluderats i ett POST-formulär.
Felsidan är dock inte särskilt användarvänlig, så du kanske vill skapa en egen vy för att hantera detta tillstånd. Detta gör du genom att ange inställningen CSRF_FAILURE_VIEW
.
CSRF-misslyckanden loggas som varningar till loggern django.security.csrf.
Använda CSRF-skydd med cachelagring¶
Om malltaggen csrf_token
används av en mall (eller om funktionen get_token
anropas på något annat sätt), kommer CsrfViewMiddleware
att lägga till en cookie och en Vary: Cookie
till svaret. Detta innebär att mellanvaran kommer att fungera bra tillsammans med cache-mellanvaran om den används enligt instruktionerna (UpdateCacheMiddleware
går före alla andra mellanvaror).
Men om du använder cachedekoratorer på enskilda vyer kommer CSRF-mellanvaran ännu inte att ha kunnat ställa in Vary-huvudet eller CSRF-cookien, och svaret kommer att cachas utan någon av dem. I det här fallet bör du på alla vyer som kräver att en CSRF-token infogas använda django.views.decorators.csrf.csrf_protect()
-dekoratorn först:
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): ...
Om du använder klassbaserade vyer kan du läsa Dekorera klassbaserade vyer.
Testning och CSRF-skydd¶
CsrfViewMiddleware
kommer vanligtvis att vara ett stort hinder för att testa vyfunktioner, på grund av behovet av CSRF-token som måste skickas med varje POST-begäran. Av denna anledning har Djangos HTTP-klient för tester modifierats för att ställa in en flagga på förfrågningar som slappnar av mellanvaran och dekoratorn csrf_protect
så att de inte längre avvisar förfrågningar. I alla andra avseenden (t.ex. skicka cookies etc.) beter de sig likadant.
Om du av någon anledning vill att testklienten ska utföra CSRF-kontroller kan du skapa en instans av testklienten som verkställer CSRF-kontroller:
>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)
Kantfall¶
Vissa vyer kan ha ovanliga krav som innebär att de inte passar in i det normala mönstret som beskrivs här. Ett antal verktyg kan vara användbara i dessa situationer. De scenarier där de kan behövas beskrivs i följande avsnitt.
Inaktivera CSRF-skydd för bara ett fåtal visningar¶
De flesta visningar kräver CSRF-skydd, men några gör det inte.
Lösning: Istället för att inaktivera middleware och tillämpa csrf_protect
på alla vyer som behöver det, aktivera middleware och använd csrf_exempt()
.
Ställa in token när CsrfViewMiddleware.process_view()
inte används¶
Det finns fall där CsrfViewMiddleware.process_view
kanske inte har körts innan din vy körs - 404- och 500-hanterare, till exempel - men du behöver fortfarande CSRF-token i ett formulär.
Lösning: använd requires_csrf_token()
Inkludera CSRF-token i en oskyddad vy¶
Det kan finnas vissa vyer som är oskyddade och har undantagits med csrf_exempt
, men som ändå måste innehålla CSRF-token.
Lösning: använd csrf_exempt()
följt av requires_csrf_token()
. (dvs. requires_csrf_token
bör vara den innersta dekoratorn).
Skyddar en vy för endast en väg¶
En vy behöver CSRF-skydd endast under en uppsättning villkor, och får inte ha det under resten av tiden.
Lösning: använd csrf_exempt()
för hela vyfunktionen, och csrf_protect()
för sökvägen inom den som behöver skyddas. Exempel:
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()
Skydda en sida som använder AJAX utan HTML-formulär¶
En sida gör en POST-begäran via AJAX, och sidan har inte ett HTML-formulär med en csrf_token
som skulle göra att den nödvändiga CSRF-cookien skickas.
Lösning: använd ensure_csrf_cookie()
på den vy som skickar sidan.
CSRF-skydd i återanvändbara applikationer¶
Eftersom det är möjligt för utvecklaren att stänga av CsrfViewMiddleware
använder alla relevanta vyer i Contrib-appar csrf_protect
-dekoratorn för att garantera säkerheten för dessa applikationer mot CSRF. Det rekommenderas att utvecklare av andra återanvändbara appar som vill ha samma garantier också använder dekoratorn csrf_protect
på sina vyer.