Cookies afschermen: samesite
httponly uit les 3 houdt scripts op je eigen pagina bij de
cookie weg. Er is nog een route naar je server: vanaf een andere site.
De browser stuurt je cookie mee bij verzoeken naar jouw site, ook als dat verzoek begint op een andere site. Stel dat je bent ingelogd op je gastenboek, en een andere pagina laat je browser op de achtergrond een verzoek naar je gastenboek sturen. Dan gaat je sessie-cookie mee, en voor je server lijkt het een verzoek van jou. Een andere site die zo jouw browser iets laat doen op een site waar jij bent ingelogd, heet CSRF, cross-site request forgery.
Wat samesite doet
Met de instelling samesite zeg je wanneer de browser de cookie meestuurt. Het
hangt af van wat er op de andere site gebeurt:
samesite | Je klikt daar op een link naar jouw site (GET) | Een formulier daar post naar jouw site (POST) | Die site start op de achtergrond een verzoek |
|---|---|---|---|
lax | mee | niet mee | niet mee |
strict | niet mee | niet mee | niet mee |
none | mee | mee | mee |
Bij none gaat de cookie alleen mee als hij ook secure heeft; daarover gaat
Er gaat iets mis.
Een klik op een link is altijd een GET-verzoek. Met lax gaat je cookie daarbij
mee, dus een endpoint dat iets verandert, mag nooit een GET zijn. Een POST
van een andere site gaat zonder cookie: je server ziet dan geen sessie, en een
endpoint dat een sessie nodig heeft, doet niets. Daarom is uitloggen in
les 5 een POST.
Is uitloggen met een POST helemaal dicht?
Niet helemaal. Het antwoord van /uitloggen zegt de browser de cookie weg te
halen, en daar luistert de browser ook na een POST van een andere site. Een
andere site kan je cookie dus laten weghalen. Je sessie op de server raakt hij
niet aan, want het verzoek kwam zonder cookie binnen.
Wat FastAPI al zet
Open het tabblad Netwerk, log in met het formulier, en klik op het verzoek
inloggen. Onder Reactieheaders staat in de regel set-cookie al
SameSite=lax. FastAPI zet samesite="lax" vanzelf, en dat is voor de meeste
sites de goede keuze. Een bezoeker die via een link van een andere site
binnenkomt, is meteen ingelogd, maar een formulier of een verzoek op de
achtergrond gaat zonder cookie.
Sites die niet alleen op de browser willen vertrouwen, zetten daarnaast een
eigen code in elk formulier. Hoe dat werkt, lees je in
de praktijk; voor je gastenboek is lax genoeg.
Zet samesite toch in je code, zodat een lezer ziet dat het een keuze is.
Vervang in inloggen de set_cookie door:
antwoord.set_cookie(
key="sessie_id",
value=sessie_id,
max_age=60 * 60 * 24 * 30,
httponly=True,
samesite="lax",
)
Log daarna opnieuw in.
Er gaat iets mis
samesite="none" zonder secure
Je zet samesite="none" om te zien wat er gebeurt, en logt opnieuw in. Maar in
het tabblad App staat bij sessie_id nog steeds Lax. Verwijder je de cookie
daar en log je nog een keer in, dan blijft App leeg. Je server zegt
Ingelogd, maar bij het volgende bericht krijg je 401: je browser stuurt geen
sessie mee.
Oorzaak: browsers bewaren een cookie met samesite="none" alleen als hij
ook secure=True heeft. Zonder secure gooit de browser de nieuwe cookie stil
weg en houdt hij de oude lax-cookie, als die er nog was.
Oplossing: gebruik lax. none heb je alleen nodig als een andere site
jouw cookie bewust moet kunnen meesturen, en dat is bij een gastenboek nooit zo.
Probeer je een instelling uit, verwijder dan eerst je oude cookie in App;
anders zie je niet wat de nieuwe doet.
Een tweede site op een andere poort krijgt je cookie wel
Je bouwt een tweede site op 127.0.0.1:8001, met een formulier dat naar
http://127.0.0.1:8000/bericht post. Je bent ingelogd en klikt op Verstuur, en
het bericht komt erin, op jouw naam.
Oorzaak: voor samesite is een site het adres zonder de poort.
127.0.0.1:8001 en 127.0.0.1:8000 zijn dus dezelfde site, en lax laat de
cookie meegaan. localhost en 127.0.0.1 zijn wel twee sites, ook al wijzen ze
naar dezelfde computer.
Oplossing: open de tweede site als http://localhost:8001. Dan is het een
andere site, en antwoordt je server met {"detail":"Log eerst in"}.
Opdrachten
Opdracht 1: Predict - Strikt
Je zet samesite="strict". Een klasgenoot is ingelogd op je gastenboek, en
klikt op de schoolsite op een link naar jouw gastenboek.
Vraag: is hij op de pagina die opent ingelogd?
Tip
Kijk in de tabel naar de kolom met de link.
Antwoord
Nee. Met strict gaat de cookie niet mee als de link op een andere site staat.
Hij ziet je gastenboek alsof hij er nieuw is. Klikt hij daarna op een link
binnen je gastenboek, dan gaat de cookie wel weer mee.
Opdracht 2: Investigate - Waarom lax?
strict stuurt de cookie in nog minder gevallen mee. Waarom is lax voor een
gastenboek toch een betere keuze?
Antwoord
Met strict is iemand die via een link binnenkomt steeds even niet ingelogd,
en dat voelt als een fout. lax houdt het verzoek op de achtergrond al tegen,
en dat is waar CSRF om draait. Een bank kiest misschien toch strict; voor een
gastenboek weegt het gemak zwaarder.
Door naar les 5: uitloggen.