0%

Origins en cross-site verzoeken · oefening

Welke cookies meegaan

Als Ana inlogt, zet het antwoord de , en een browser legt die in zijn cookiejar. In het model is de jar een , en een cookie een . Hier zijn de uit hoofdstuk 4 en de dict die ervan wordt, met de ingekort. De header is één regel, hier na Max-Age afgebroken zodat hij op de pagina past:

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 is de host die de cookie zette. samesite is "Strict", "Lax", "None", of "" voor een cookie die er geen noemt.

Bij elk verzoek dat een pagina begint, vraagt de browser van elke cookie in de jar: gaat deze mee? Er zijn vier tests, in deze volgorde: host, pad, Secure, SameSite. Een cookie die er één niet doorstaat, blijft thuis. cookies_to_send(jar, url, page_origin, *, method, top_level) is die . url is waar het verzoek naartoe gaat, en page_origin is de van de pagina die het begon.

Host

De cookie gaat alleen naar de exacte host die hem zette: cookie["host"] moet gelijk zijn aan urlsplit(url).hostname. De sessiecookie noemt geen Domain, dus app.reading.example krijgt hem nooit.

De test vergelijkt hosts, geen origins. Een cookie is niet aan een gebonden, dus een verzoek aan https://reading.example:8443 draagt de cookies van https://reading.example.

De jar bevat de sessiecookie van reading.example. Een verzoek gaat naar https://reading.example:8443/me vanaf een pagina van de leeslijst. Gaat de cookie mee?

Pad

Een cookie gaat naar zijn eigen pad en naar elk pad daaronder. path_matches(cookie_path, request_path) is in drie gevallen waar:

  1. de twee paden zijn gelijk;

  2. het verzoekpad begint met het cookiepad, en het cookiepad eindigt op /;

  3. het verzoekpad begint met het cookiepad, en het volgende teken is /.

Dus Path=/books matcht /books/7. Het matcht niet /booksx, dat met dezelfde letters begint en een ander pad is. Path=/ matcht alles. Een zonder pad, zoals https://reading.example, vraagt om /.

Een cookie heeft Path=/books. Welk verzoekpad matcht hij?

Secure

Een Secure-cookie gaat alleen naar een https-URL. with Python liet Secure weg, omdat de server daar gewoon HTTP sprak. Hoofdstuk 4 zette het aan. Deze test is de regel die de vlag betekenis geeft.

SameSite

Eerst vraagt de browser of het verzoek binnen één site blijft: same_site(page_origin, url), met je uit les 2. Als dat zo is, mag elke cookie mee. Zo niet, dan beslist het attribuut:

  • Strict: de cookie blijft thuis.

  • Lax: de cookie gaat alleen mee met een top-level navigatie waarvan de GET of HEAD is. In het model zijn een gevolgde link en een verstuurd formulier top-level navigaties: het antwoord wordt de pagina die de lezer ziet. Een afbeelding en een verzoek dat een script doet, zijn dat niet. Een link is een GET, een formulier kan GET of POST sturen, en geen enkele paginanavigatie gebruikt HEAD. Over sites heen laat Lax de cookie dus meegaan met een gevolgde link of een formulier dat met GET wordt verstuurd, en nooit met een formulier-POST, een afbeelding of het verzoek van een script. Daarom staat les 8 erop dat geen enkele GET iets verandert.

  • None: de cookie gaat altijd mee.

  • Geen attribuut: dit model behandelt de cookie als Lax, zoals Chromium doet.

samesite_allows(samesite, *, same_site_request, method, top_level) antwoordt voor één cookie. De * maakt de drie namen erna keyword-only. De meegeleverde set LAX_METHODS bevat "GET" en "HEAD". Vier antwoorden in deze tabel zijn voor jou:

SameSiteHet verzoekGaat mee?
Strictbinnen de siteja
Strictcross-site linknee
Strictcross-site formulier-POSTnee
Laxbinnen de siteja
Laxcross-site linkja
Laxcross-site formulier-POSTnee
Laxcross-site afbeelding?
Nonecross-site formulier-POST?
Nonecross-site afbeeldingja
(ontbreekt)cross-site linkja
(ontbreekt)cross-site formulier-POST?
(ontbreekt)cross-site afbeelding?

Een pagina op https://other.example bevat een formulier dat naar https://reading.example/books/delete post. De sessiecookie is SameSite=Lax. Gaat hij mee?

Wat een browser weigert te bewaren

Sommige cookies bereiken de jar nooit. may_store(cookie, url) geeft voor drie ervan False terug:

  • een Secure-cookie die is gezet door een antwoord van een http-URL;

  • een cookie met SameSite=None en zonder Secure;

  • een cookie waarvan de naam met __Host- begint en die niet Secure is, of waarvan het pad niet / is.

Hoofdstuk 4 koos het voorvoegsel __Host- als belofte. Hier is de code die een server eraan houdt.

Een antwoord zet __Host-session=abc; Path=/; HttpOnly zonder Secure. Wat doet de browser van het model?

Je opdracht

Schrijf in mini_browser.py de vier functies die voor les 3 zijn gemarkeerd, in deze volgorde: path_matches, samesite_allows, may_store, cookies_to_send. De laatste loopt de jar door, past de vier tests toe met continue, en geeft een nieuwe lijst terug met de cookies die meegaan, in de volgorde van de jar. Hij verandert de jar nooit.

Vul elk vraagteken in door het je functie te vragen. Deze regel vraagt naar het eerste:

python -c "import mini_browser; print(mini_browser.samesite_allows('Lax', same_site_request=False, method='GET', top_level=False))"

tests/steps.py bevat de vier pagina-origins als OWN, APP, NOTES en OTHER. Schrijf daarna twee tests in tests/test_browser.py. Elk bouwt een jar met één cookie-dict zoals die bovenaan deze pagina en roept mini_browser.cookies_to_send aan voor een formulier-POST naar steps.OWN + "/books/delete", met method="POST" en top_level=True:

  • test_lax_cookie_stays_home_on_a_cross_site_post: vanaf steps.OTHER is het resultaat [].

  • test_lax_cookie_travels_within_the_site: vanaf steps.NOTES is het resultaat gelijk aan de jar.

Voer daarna beide uit:

python -m pytest -q tests/test_browser.py
python mini_browser.py

De eerste eindigt op 2 passed. In de tabel van de tweede staat in de laatste kolom nu True, True, True, False: van de vier pagina’s post alleen die op other.example zijn formulier zonder de cookie.

Waar het model en echte browsers in deze les verschillen:

  • Een ontbrekende SameSite. Het model behandelt die als Lax, zoals Chromium doet en zoals de huidige draft van de cookiestandaard zegt. Chromium laat zo’n cookie in de eerste twee minuten ook meegaan met een cross-site top-level POST, een die de draft toestaat. Firefox en Safari behandelen een ontbrekende SameSite als None.

  • SameSite=None zonder Secure. Chromium en Firefox weigeren die te bewaren, zoals het model doet. Safari bewaart hem.

  • Het schema in een site. Chromium telt http://reading.example en https://reading.example als twee sites, zoals het model doet. Firefox en Safari tellen ze als één wanneer ze SameSite toepassen.

  • localhost. Chrome en Firefox accepteren een Secure-cookie van http://localhost, en Safari niet. Het model accepteert er geen.

  • Het voorvoegsel. De draft matcht __Host- zonder op hoofdletters te letten, en het model matcht het exact.

  • Weggelaten. Het attribuut Domain, verloop op tijd, het partitioneren van cookies en het blokkeren van cookies die naar een derde partij worden gestuurd.

Klik daarna op Check my work.

Opdracht

Schrijf in mini_browser.py de regels die beslissen welke een verzoek draagt, en twee tests ervan.

Een cookie is een met de sleutels name, value, host, path, secure (True of False) en samesite ("Strict", "Lax", "None", of "" als de cookie er geen noemt). Een jar is een van zulke dicts.

  • path_matches(cookie_path, request_path) geeft True terug als de paden gelijk zijn, of als het verzoekpad met het cookiepad begint en het cookiepad op / eindigt of het volgende teken van het verzoekpad / is. Anders geeft hij False terug.

  • samesite_allows(samesite, *, same_site_request, method, top_level) geeft True terug voor "None", en voor elke als same_site_request waar is. Over sites heen krijgt "Strict" de waarde False, en krijgen "Lax" en "" alleen True als top_level waar is en method in LAX_METHODS zit.

  • may_store(cookie, url) geeft False terug voor een Secure-cookie als url geen https- is, voor SameSite=None zonder Secure, en voor een naam die met __Host- begint als de cookie niet Secure is of zijn pad niet / is. Anders geeft hij True terug.

  • cookies_to_send(jar, url, page_origin, *, method, top_level) geeft een nieuwe lijst terug met de cookies uit jar die met het verzoek meegaan, in de volgorde van de jar. Een cookie gaat mee als zijn host gelijk is aan de host van url, zijn pad matcht met het pad van url (een leeg pad telt als /), hij niet Secure is of url een https-URL is, en samesite_allows ja zegt voor same_site(page_origin, url). De jar wordt niet veranderd.

Schrijf in tests/test_browser.py, onder het commentaar van hoofdstuk 8, twee tests. Elk roept mini_browser.cookies_to_send aan met een jar die één Lax-cookie van de host reading.example bevat, voor een POST naar steps.OWN + "/books/delete" met top_level=True:

  • test_lax_cookie_stays_home_on_a_cross_site_post: begonnen door een pagina op steps.OTHER, is het resultaat [].

  • test_lax_cookie_travels_within_the_site: begonnen door een pagina op steps.NOTES, is het resultaat gelijk aan de jar.

Voer python -m pytest -q tests/test_browser.py en python mini_browser.py uit.

Klik daarna op Check my work. Die roept de vier aan met waarden die je nog niet hebt gezien. path_matches krijgt tien paren paden. samesite_allows krijgt elke waarde van het attribuut met verzoeken binnen de site en over sites heen, met GET, HEAD, POST en DELETE, en met beide waarden van top_level. may_store krijgt tien cookies, waarvan één met __Host- midden in de naam. cookies_to_send krijgt een jar van acht cookies en veertien verzoeken: naar een dieper pad, naar een pad dat alleen met dezelfde letters begint, naar een URL zonder pad, naar een http-URL, naar een andere , naar een andere host van de site, en vanaf pagina’s binnen de site, op een andere site en aan de http-kant van dezelfde host. De jar wordt ervoor en erna vergeleken. Als laatste draait hij je twee tests op naam, één keer: elk moet slagen, en elk moet mini_browser.cookies_to_send via de aanroepen. Niets uit je wordt beoordeeld.