Cookies afschermen: de zwakheid
Het sessie-id uit Sessies is de sleutel tot een sessie: wie het heeft, is voor je server die bezoeker. Daarom is het een lang, willekeurig getal dat niemand raadt. Maar raden hoeft niet als een script het kan lezen, en standaard kan dat.
Een formulier bij de server
Neem de server uit Wie mag wat: de oplossing en zet er
een formulier bij, als los bestand static/formulier.html:
<!doctype html>
<html>
<body>
<form method="post" action="/bericht">
<input type="text" name="naam" placeholder="Je naam" required>
<input type="text" name="bericht" placeholder="Je bericht" required>
<button type="submit">Verstuur</button>
</form>
</body>
</html>
In main.py komen er twee regels bij, zodat de server de map static laat
zien:
from fastapi.staticfiles import StaticFiles
app.mount("/static", StaticFiles(directory="static"), name="static")
Zet de import bovenaan bij de andere, en app.mount direct onder
app = FastAPI().
Bekijk je eigen cookie
Kijk alleen naar de cookies van je eigen server op 127.0.0.1, in je eigen
browser. Het sessie-id van een ander gebruiken om als die persoon binnen te
komen, is strafbaar.
- Open
http://127.0.0.1:8000/static/formulier.htmlen verstuur een bericht. Je ziet de sleutel van je bericht als JSON. - Ga terug naar het formulier en open de ontwikkelaarstools. Kijk in het
tabblad App (Firefox: Opslag) onder Cookies bij
http://127.0.0.1:8000. Daar staatsessie_id, met in de kolom HttpOnly niets. - Typ in de Console:
document.cookie
De Console antwoordt met je sessie-id, iets als
'sessie_id=bb4b18ca1efc4877c990fdadd8a6f593'.
document.cookie is niet alleen voor jou in de Console. Elk script dat op deze
pagina draait, kan het ook, en daar zit de zwakheid. Staat er ergens een gat
zoals in HTML van een bezoeker, dan draait er misschien een
script van een ander op je pagina, en dat leest je sessie-id net zo makkelijk.
Er gaat iets mis
document.cookie geeft '', een lege tekst, terwijl je wel een bericht hebt
verstuurd.
Oorzaak: je hebt de pagina geopend via localhost:8000 in plaats van
127.0.0.1:8000, of andersom. Het is dezelfde server, maar voor de browser zijn
het twee verschillende sites, elk met eigen cookies.
Oplossing: gebruik overal hetzelfde adres. Verstuur het bericht en open de
Console op 127.0.0.1:8000.
Opdrachten
Opdracht 1: Investigate - Wat stuurt de server mee?
Open het tabblad Netwerk, verstuur nog een bericht, en klik op het verzoek
bericht. Zoek bij de antwoordkoppen de regel set-cookie. Welke instellingen
zie je achter het sessie-id staan?
Tip
De instellingen staan achter de waarde, gescheiden door puntkomma's.
Antwoord
Iets als:
sessie_id=bb4b18ca1efc4877c990fdadd8a6f593; Max-Age=2592000; Path=/; SameSite=lax
Max-Age is de 30 dagen uit max_age in
seconden, Path=/ betekent: voor de hele site. SameSite=lax zet FastAPI er
vanzelf bij; wat dat doet, staat in de praktijk. HttpOnly
staat er niet bij, en daarom mag een script de cookie lezen.
Opdracht 2: Predict - Een ander tabblad
Je opent in hetzelfde browservenster een tweede tabblad met
http://127.0.0.1:8000/berichten, en typt daar in de Console
document.cookie.
Vraag: zie je daar ook je sessie-id?
Antwoord
Ja. Een cookie hoort bij de site, niet bij één pagina of tabblad. Met Path=/
geldt hij voor elke pagina op 127.0.0.1:8000, en een script op elk van die
pagina's kan hem lezen.
Door naar stap 2: de oplossing.