Skydd mot Cross Site Request Forgery¶
CSRF middleware och template tag ger ett lättanvänt skydd mot Cross Site Request Forgeries. Denna typ av attack inträffar när en skadlig webbplats innehåller en länk, en formulärknapp eller JavaScript som är avsedd att utföra någon åtgärd på din webbplats med hjälp av inloggningsuppgifterna för en inloggad användare som besöker den skadliga webbplatsen i sin webbläsare. En relaterad typ av attack, ”login CSRF”, där en angripande webbplats lurar en användares webbläsare att logga in på en webbplats med någon annans inloggningsuppgifter, omfattas också.
Det första försvaret mot CSRF-attacker är att se till att GET-begäranden (och andra ”säkra” metoder, enligt definitionen i RFC 9110 Section 9.2.1) är bieffektsfria. Förfrågningar via ”osäkra” metoder, som POST, PUT och DELETE, kan sedan skyddas genom de steg som beskrivs i Så här använder du Djangos CSRF-skydd.
Hur det fungerar¶
CSRF-skyddet baseras på följande saker:
En CSRF-cookie som är ett slumpmässigt hemligt värde, som andra webbplatser inte har tillgång till.
CsrfViewMiddleware
skickar denna cookie med svaret närdjango.middleware.csrf.get_token()
anropas. Den kan också skicka den i andra fall. Av säkerhetsskäl ändras värdet på hemligheten varje gång en användare loggar in.Ett dolt formulärfält med namnet ”csrfmiddlewaretoken”, som finns i alla utgående POST-formulär.
För att skydda mot BREACH-attacker är värdet i detta fält inte bara hemligheten. Det krypteras på olika sätt för varje svar med hjälp av en mask. Masken genereras slumpmässigt vid varje anrop till
get_token()
, så formulärfältets värde är olika varje gång.Denna del görs av
csrf_token
malltagg.För alla inkommande förfrågningar som inte använder HTTP GET, HEAD, OPTIONS eller TRACE måste en CSRF-cookie finnas och fältet ”csrfmiddlewaretoken” måste finnas och vara korrekt. Om så inte är fallet kommer användaren att få ett 403-fel.
Vid validering av fältvärdet ”csrfmiddlewaretoken” jämförs endast hemligheten, inte hela token, med hemligheten i cookie-värdet. Detta gör det möjligt att använda ständigt föränderliga token. Även om varje begäran kan använda sin egen token förblir hemligheten gemensam för alla.
Denna kontroll görs av
CsrfViewMiddleware
.CsrfViewMiddleware
verifierar Origin header, om det tillhandahålls av webbläsaren, mot den aktuella värden och inställningenCSRF_TRUSTED_ORIGINS
. Detta ger skydd mot attacker över flera underdomäner.Dessutom, för HTTPS-förfrågningar, om
Origin
-headern inte tillhandahålls, utförCsrfViewMiddleware
strikt referer-kontroll. Detta innebär att även om en underdomän kan ställa in eller ändra cookies på din domän, kan den inte tvinga en användare att posta till din applikation eftersom den begäran inte kommer från din egen exakta domän.Detta hanterar också en man-in-the-middle-attack som är möjlig under HTTPS när en sessionsoberoende hemlighet används, på grund av att HTTP
Set-Cookie
-rubriker (tyvärr) accepteras av klienter även när de pratar med en webbplats under HTTPS. (Referer-kontroll görs inte för HTTP-förfrågningar eftersom närvaron avReferer
-rubriken inte är tillräckligt tillförlitlig under HTTP)Om inställningen
CSRF_COOKIE_DOMAIN
är angiven jämförs referensen mot den. Du kan tillåta förfrågningar över underdomäner genom att inkludera en inledande punkt. Till exempel: kommerCSRF_COOKIE_DOMAIN = '.example.com'
att tillåta POST-förfrågningar frånwww.example.com
ochapi.example.com
. Om inställningen inte är angiven måste referensen matcha HTTP-rubrikenHost
.Att utöka de accepterade referenserna utöver den aktuella värd- eller cookiedomänen kan göras med inställningen
CSRF_TRUSTED_ORIGINS
.
Detta säkerställer att endast formulär som kommer från betrodda domäner kan användas för att skicka tillbaka data.
Den ignorerar avsiktligt GET-begäranden (och andra begäranden som definieras som ”säkra” av RFC 9110 Section 9.2.1). Dessa förfrågningar borde aldrig ha några potentiellt farliga bieffekter, och därför borde en CSRF-attack med en GET-förfrågan vara ofarlig. RFC 9110 Section 9.2.1 definierar POST, PUT och DELETE som ”osäkra”, och alla andra metoder antas också vara osäkra, för maximalt skydd.
CSRF-skyddet kan inte skydda mot man-in-the-middle-attacker, så använd HTTPS med HTTP Strict Transport Security. Det förutsätter också validering av HOST-headern och att det inte finns några cross-site scripting-sårbarheter på din webbplats (eftersom XSS-sårbarheter redan låter en angripare göra allt som en CSRF-sårbarhet tillåter och mycket värre).
Ta bort rubriken Referer
För att undvika att avslöja referentens URL till tredjepartswebbplatser kanske du vill inaktivera referenten på webbplatsens <a>
-taggar. Du kan till exempel använda taggen <meta name="referrer" content="no-referrer">
eller inkludera rubriken Referrer-Policy: no-referrer
. På grund av CSRF-skyddets strikta referer-kontroll på HTTPS-förfrågningar orsakar dessa tekniker ett CSRF-misslyckande på förfrågningar med ”osäkra” metoder. Använd istället alternativ som <a rel="noreferrer" ...>"
för länkar till tredjepartswebbplatser.
Begränsningar¶
Underdomäner inom en webbplats kommer att kunna ställa in cookies på klienten för hela domänen. Genom att ställa in cookien och använda en motsvarande token kan underdomäner kringgå CSRF-skyddet. Det enda sättet att undvika detta är att se till att underdomäner kontrolleras av betrodda användare (eller åtminstone inte kan ställa in cookies). Observera att även utan CSRF finns det andra sårbarheter, t.ex. sessionsfixering, som gör att det är en dålig idé att ge underdomäner till icke betrodda parter, och dessa sårbarheter kan inte enkelt åtgärdas med nuvarande webbläsare.
Verktyg¶
Exemplen nedan förutsätter att du använder funktionsbaserade vyer. Om du arbetar med klassbaserade vyer kan du läsa Dekorera klassbaserade vyer.
- csrf_exempt(view)[source]¶
Denna dekorator markerar att en vy är undantagen från det skydd som säkerställs av mellanvaran. Exempel:
from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt def my_view(request): return HttpResponse("Hello world")
- csrf_protect(view)¶
Dekoratör som ger skydd av
CsrfViewMiddleware
till en vy.Användning:
from django.shortcuts import render from django.views.decorators.csrf import csrf_protect @csrf_protect def my_view(request): c = {} # ... return render(request, "a_template.html", c)
- requires_csrf_token(view)¶
Normalt fungerar inte malltaggen
csrf_token
om inteCsrfViewMiddleware.process_view
eller motsvarande somcsrf_protect
har körts. Vydekoratornrequires_csrf_token
kan användas för att säkerställa att malltaggen fungerar. Denna dekorator fungerar på liknande sätt somcsrf_protect
, men avvisar aldrig en inkommande begäran.Exempel:
from django.shortcuts import render from django.views.decorators.csrf import requires_csrf_token @requires_csrf_token def my_view(request): c = {} # ... return render(request, "a_template.html", c)
- ensure_csrf_cookie(view)¶
Denna dekorator tvingar en vy att skicka CSRF-cookien.
Inställningar¶
Ett antal inställningar kan användas för att styra Djangos CSRF-beteende:
Vanliga frågor¶
Är det ett problem att Djangos CSRF-skydd inte är kopplat till en session som standard?¶
Nej, detta är avsiktligt. Att inte koppla CSRF-skydd till en session gör det möjligt att använda skyddet på webbplatser som en pastebin som tillåter inskick från anonyma användare som inte har en session.
Om du vill lagra CSRF-token i användarens session ska du använda inställningen CSRF_USE_SESSIONS
.
Varför kan en användare stöta på ett CSRF-valideringsfel efter att ha loggat in?¶
Av säkerhetsskäl roteras CSRF-tokens varje gång en användare loggar in. Alla sidor med ett formulär som genereras före en inloggning kommer att ha en gammal, ogiltig CSRF-token och måste laddas om. Detta kan hända om en användare använder bakåtknappen efter en inloggning eller om de loggar in i en annan webbläsarflik.