Origins und Cross-Site-Anfragen · Übung
Welche Cookies mitgehen
Wenn Ana sich anmeldet, setzt die Antwort das Max-Age umbrochen, damit er auf die Seite passt:
set-cookie: __Host-session=<22 characters>; HttpOnly; Max-Age=28800;
Path=/; SameSite=Lax; Secure
{
"name": "__Host-session",
"value": "<22 characters>",
"host": "reading.example",
"path": "/",
"secure": True,
"samesite": "Lax",
}
host ist der Host, der das Cookie gesetzt hat. samesite ist "Strict", "Lax", "None" oder "" für ein Cookie, das keins nennt.
Bei jeder Anfrage, die eine Seite startet, fragt der Browser jedes Cookie im Speicher: Geht dieses mit? Es gibt vier Prüfungen, in dieser Reihenfolge: Host, Pfad, Secure, SameSite. Ein Cookie, das eine nicht besteht, bleibt zu Hause. cookies_to_send(jar, url, page_origin, *, method, top_level) ist diese url ist das Ziel der Anfrage, und page_origin ist die
Host
Das Cookie geht nur an genau den Host, der es gesetzt hat: cookie["host"] muss gleich urlsplit(url).hostname sein. Das Session-Cookie nennt keine Domain, also bekommt app.reading.example es nie.
Die Prüfung vergleicht Hosts, nicht Origins. Ein Cookie ist an keinen https://reading.example:8443 die Cookies von https://reading.example.
Der Speicher enthält das Session-Cookie von reading.example. Eine Anfrage geht von einer Seite der Leseliste an https://reading.example:8443/me. Geht das Cookie mit?
Pfad
Ein Cookie geht an seinen eigenen Pfad und an jeden Pfad darunter. path_matches(cookie_path, request_path) ist in drei Fällen wahr:
die beiden Pfade sind gleich;
der Anfragepfad beginnt mit dem Cookie-Pfad, und der Cookie-Pfad endet auf
/;der Anfragepfad beginnt mit dem Cookie-Pfad, und sein nächstes Zeichen ist
/.
Also passt Path=/books zu /books/7. Es passt nicht zu /booksx, das mit denselben Buchstaben beginnt und ein anderer Pfad ist. Path=/ passt zu allem. Eine https://reading.example, fragt nach /.
Ein Cookie hat Path=/books. Zu welchem Anfragepfad passt es?
Secure
Ein Secure-Cookie geht nur an eine https-URL. Secure weggelassen, weil sein Server einfaches HTTP sprach. Kapitel 4 hat es eingeschaltet. Diese Prüfung ist die Regel, die dem Flag Bedeutung gibt.
SameSite
Zuerst fragt der Browser, ob die Anfrage innerhalb einer Site bleibt: same_site(page_origin, url), mit deiner
Strict: Das Cookie bleibt zu Hause.Lax: Das Cookie geht nur bei einer Top-Level-Navigation mit, derenGET oder HEAD ist. Im Modell sind ein angeklickter Link und ein abgeschicktes Formular Top-Level-Navigationen: Die Antwort wird zu der Seite, die der Leser sieht. Ein Bild und eine Anfrage, die ein Skript stellt, sind es nicht. Ein Link ist ein GET, ein Formular kann GET oder POST senden, und keine Seitennavigation verwendet HEAD. Über Sites hinweg lässt Laxdas Cookie also bei einem angeklickten Link oder einem mit GET gesendeten Formular mitgehen und nie bei einem Formular-POST, einem Bild oder der Anfrage eines Skripts. Deshalb besteht Lektion 8 darauf, dass kein GET etwas ändert.None: Das Cookie geht immer mit.Kein Attribut: Dieses Modell behandelt das Cookie als
Lax, wie Chromium.
samesite_allows(samesite, *, same_site_request, method, top_level) antwortet für ein Cookie. Das * macht die drei Namen danach zu reinen Schlüsselwortargumenten. Das mitgelieferte Set LAX_METHODS enthält "GET" und "HEAD". Vier Antworten in dieser Tabelle bleiben dir überlassen:
SameSite | Die Anfrage | Geht mit? |
|---|---|---|
Strict | innerhalb der Site | ja |
Strict | Cross-Site-Link | nein |
Strict | Cross-Site-Formular-POST | nein |
Lax | innerhalb der Site | ja |
Lax | Cross-Site-Link | ja |
Lax | Cross-Site-Formular-POST | nein |
Lax | Cross-Site-Bild | ? |
None | Cross-Site-Formular-POST | ? |
None | Cross-Site-Bild | ja |
| (fehlt) | Cross-Site-Link | ja |
| (fehlt) | Cross-Site-Formular-POST | ? |
| (fehlt) | Cross-Site-Bild | ? |
Eine Seite auf https://other.example enthält ein Formular, das an https://reading.example/books/delete postet. Das Session-Cookie ist SameSite=Lax. Geht es mit?
Was ein Browser nicht speichert
Manche Cookies erreichen den Speicher nie. may_store(cookie, url) gibt für drei davon False zurück:
ein
Secure-Cookie, das eine Antwort von einerhttp-URL setzt;ein Cookie mit
SameSite=Noneund ohneSecure;ein Cookie, dessen Name mit
__Host-beginnt und das nichtSecureist oder dessen Pfad nicht/ist.
Kapitel 4 hat das Präfix __Host- als Versprechen gewählt. Hier ist der Code, der einen Server daran festhält.
Eine Antwort setzt __Host-session=abc; Path=/; HttpOnly ohne Secure. Was tut der Browser des Modells?
Deine Aufgabe
Schreibe in mini_browser.py die vier Funktionen, die für Lektion 3 markiert sind, in dieser Reihenfolge: path_matches, samesite_allows, may_store, cookies_to_send. Die letzte geht den Speicher durch, wendet die vier Prüfungen mit continue an und gibt eine neue Liste der Cookies zurück, die mitgehen, in der Reihenfolge des Speichers. Sie ändert den Speicher nie.
Fülle jedes Fragezeichen, indem du deine Funktion fragst. Diese Zeile fragt nach dem ersten:
python -c "import mini_browser; print(mini_browser.samesite_allows('Lax', same_site_request=False, method='GET', top_level=False))"
tests/steps.py enthält die vier Seiten-Origins als OWN, APP, NOTES und OTHER. Schreibe dann zwei Tests in tests/test_browser.py. Jeder baut einen Speicher mit einem Cookie-Dict wie dem oben auf dieser Seite und ruft mini_browser.cookies_to_send für einen Formular-POST an steps.OWN + "/books/delete" auf, mit method="POST" und top_level=True:
test_lax_cookie_stays_home_on_a_cross_site_post: vonsteps.OTHERaus ist das Ergebnis[].test_lax_cookie_travels_within_the_site: vonsteps.NOTESaus ist das Ergebnis gleich dem Speicher.
Führe dann beide aus:
python -m pytest -q tests/test_browser.py
python mini_browser.py
Der erste endet mit 2 passed. In der Tabelle des zweiten zeigt die letzte Spalte jetzt True, True, True, False: Von den vier Seiten postet nur die auf other.example ihr Formular ohne das Cookie.
Wo sich Modell und echte Browser in dieser Lektion unterscheiden:
Ein fehlendes
SameSite. Das Modell behandelt es alsLax, wie Chromium und wie der aktuelle Entwurf des Cookie-Standards es sagt. Chromium lässt ein solches Cookie außerdem in seinen ersten zwei Minuten bei einem Cross-Site-Top-Level-POST mitgehen, eine, die der Entwurf erlaubt. Firefox und Safari behandeln ein fehlendes SameSitealsNone.SameSite=NoneohneSecure. Chromium und Firefox weigern sich, es zu speichern, wie das Modell. Safari speichert es.Das Schema in einer Site. Chromium zählt
http://reading.exampleundhttps://reading.exampleals zwei Sites, wie das Modell. Firefox und Safari zählen sie als eine, wenn sieSameSiteanwenden.localhost. Chrome und Firefox akzeptieren einSecure-Cookie vonhttp://localhost, Safari nicht. Das Modell akzeptiert keins.Das Präfix. Der Entwurf erkennt
__Host-ohne Rücksicht auf Groß- und Kleinschreibung, das Modell erkennt es nur genau so.Weggelassen. Das Attribut
Domain, der zeitliche Ablauf, die Partitionierung von Cookies und das Blockieren von Cookies, die an Dritte gesendet werden.
Klicke dann auf Check my work.
Aufgabe
Schreibe in mini_browser.py die Regeln, die entscheiden, welche
Ein Cookie ist ein name, value, host, path, secure (True oder False) und samesite ("Strict", "Lax", "None" oder "", wenn das Cookie keins nennt). Ein Speicher ist eine
path_matches(cookie_path, request_path)gibtTruezurück, wenn die Pfade gleich sind oder wenn der Anfragepfad mit dem Cookie-Pfad beginnt und entweder der Cookie-Pfad auf/endet oder das nächste Zeichen des Anfragepfads/ist. Andernfalls gibt sieFalsezurück.samesite_allows(samesite, *, same_site_request, method, top_level)gibtTruezurück für"None"und für jeden, wenn same_site_requestwahr ist. Über Sites hinweg bekommt"Strict"False, und"Lax"und""bekommenTruenur, wenntop_levelwahr ist undmethodinLAX_METHODSliegt.may_store(cookie, url)gibtFalsezurück für einSecure-Cookie, wennurlkeinehttps-ist, für SameSite=NoneohneSecureund für einen Namen, der mit__Host-beginnt, wenn das Cookie nichtSecureist oder sein Pfad nicht/ist. Andernfalls gibt sieTruezurück.cookies_to_send(jar, url, page_origin, *, method, top_level)gibt eine neue Liste mit den Cookies ausjarzurück, die mit der Anfrage mitgehen, in der Reihenfolge des Speichers. Ein Cookie geht mit, wenn seinhostgleich dem Host vonurlist, sein Pfad zum Pfad vonurlpasst (ein leerer Pfad zählt als/), es nichtSecureist oderurleinehttps-URL ist undsamesite_allowsfürsame_site(page_origin, url)ja sagt. Der Speicher wird nicht verändert.
Schreibe in tests/test_browser.py unter dem Kommentar zu Kapitel 8 zwei Tests. Jeder ruft mini_browser.cookies_to_send mit einem Speicher auf, der ein Lax-Cookie des Hosts reading.example enthält, für einen POST an steps.OWN + "/books/delete" mit top_level=True:
test_lax_cookie_stays_home_on_a_cross_site_post: gestartet von einer Seite aufsteps.OTHERist das Ergebnis[].test_lax_cookie_travels_within_the_site: gestartet von einer Seite aufsteps.NOTESist das Ergebnis gleich dem Speicher.
Führe python -m pytest -q tests/test_browser.py und python mini_browser.py aus.
Klicke dann auf Check my work. Es ruft die vier path_matches bekommt zehn Pfadpaare. samesite_allows bekommt jeden Wert des Attributs mit Anfragen innerhalb der Site und über Sites hinweg, mit GET, HEAD, POST und DELETE und mit beiden Werten von top_level. may_store bekommt zehn Cookies, eines davon mit __Host- mitten im Namen. cookies_to_send bekommt einen Speicher mit acht Cookies und vierzehn Anfragen: an einen tieferen Pfad, an einen Pfad, der nur mit denselben Buchstaben beginnt, an eine URL ohne Pfad, an eine http-URL, an einen anderen http-Seite desselben Hosts. Der Speicher wird vorher und nachher verglichen. Zuletzt führt es deine zwei Tests einmal namentlich aus: Jeder muss bestehen, und jeder muss mini_browser.cookies_to_send über das