0%

Hoofdstuk 9

CORS

Toestemming om te lezen

Hoofdstuk 8 ging over een verzoek dat een andere pagina niet zou moeten kunnen doen. Dit hoofdstuk begint bij de omgekeerde wens.

De leeslijst krijgt een tweede frontend, op https://app.reading.example. Dat is een van de vier namen uit hoofdstuk 8, en hij is van jou. Een script op de pagina’s daarvan wil GET https://reading.example/about sturen en het antwoord tonen.

De twee hosts zijn één site en twee . Je weet wat er volgt uit les 4 van hoofdstuk 8: het verzoek wordt verstuurd, de server antwoordt, en de houdt het antwoord weg bij de pagina. Die regel beschermde ana tegen de pagina’s van de buurman. Hier houdt hij een pagina tegen die je zelf hebt geschreven.

De server mag ja zeggen

De same-origin policy heeft één , en die heeft de server in handen. Een antwoord mag een header dragen die een origin noemt:

access-control-allow-origin: https://app.reading.example

Met die header zegt de server: een pagina op deze origin mag dit antwoord lezen. Die afspraak heet , van cross-origin resource sharing. Voor een gewone GET gaat dat in vier stappen.

the page on           the browser         the server at
app.reading.example                       reading.example

1. asks for GET /about
   ----------------->
                      2. sends the request, and adds
                         origin: https://app.reading.example
                         --------------->
                                          3. answers as always,
                                             and may add
                                             access-control-allow-origin
                         <---------------
                      4. looks at that header, and hands
   <---------------      the response over, or keeps it
  1. Het script van de pagina vraagt zijn browser om het verzoek.

  2. De browser verstuurt het. Omdat het verzoek naar een andere origin gaat, voegt de browser een header Origin toe met de origin van de pagina. De pagina kan die header niet veranderen.

  3. De server antwoordt zoals altijd. Als hij wil, voegt hij Access-Control-Allow-Origin toe.

  4. De browser kijkt naar die ene header. Hij geeft het antwoord alleen aan het script als de header de origin van de pagina noemt, of als hij * is, wat voor elke origin staat. In alle andere gevallen krijgt het script niets.

Kijk wie er in elke stap handelt. De server geeft de toestemming in de derde stap. De browser dwingt hem af in de vierde. De pagina heeft helemaal niets te zeggen.

De header Origin uit de tweede stap is dezelfde die je server al leest. In hoofdstuk 8 gebruikte hij die header om een vervalste POST te weigeren. Nu vertelt dezelfde header de server welke pagina het vraagt, zodat hij die pagina bij naam kan antwoorden.

Volg het

Het volgende blok is de vierde stap: een antwoord- in de vorm die je server teruggeeft, en de controle die een browser doet. Voer het uit. Haal daarna de header uit de dict, verander hem in "*", of verander PAGE in "https://notes.reading.example", en voer het elke keer opnieuw uit.

Try it

Dit blok is een schets van de regel, en het verstuurt niets. In les 2 schrijf je de echte controle in mini_browser.py.

Wie beslist er bij elk verzoek of een pagina een antwoord van een andere origin mag lezen?

Wat de server deed voordat de browser besliste

Bij de vierde stap is de server klaar. Hij ontving het verzoek, voerde handle() uit en stuurde het hele antwoord. Als de browser het lezen weigert, wordt er niets teruggedraaid. Het antwoord kwam aan, en het werd voor een script achtergehouden.

Een ontbrekende header maakt dus nooit iets ongedaan. Als het verzoek iets op de server veranderde, is die verandering gedaan. Dat is nog eens de les van hoofdstuk 8: lezen is wat de browser bewaakt, en een verzoek dat iets verandert, heeft dat al gedaan voordat er naar een header wordt gekeken.

Een pagina op een andere origin post een formulier, en de server voert het uit. Het antwoord heeft geen Access-Control-Allow-Origin. Wat klopt er?

Geen browser, geen CORS

Alles hierboven is een belofte die browsers nakomen. wire.py doet zo’n belofte niet. Het stuurt de bytes die je typt en drukt elke byte af die terugkomt, welke headers het antwoord ook heeft. Dat doet pl_sec.py ook, en elk programma dat iemand met een schrijft.

Een header Access-Control-Allow-Origin vraagt alleen iets van browsers. Als je hem weglaat, verberg je niets voor een programma dat geen browser is. Onthoud dat in dit hoofdstuk: wat geheim of onveranderd moet blijven, heeft nog steeds de controles van hoofdstuk 4 tot en met 8 nodig, de , het token, de eigenaar van een boek en de controle van Origin.

wire.py stuurt GET /about, en het antwoord heeft geen CORS-header. Kan het de body lezen?

Dat is de hele uitwisseling voor een gewone GET. Twee gevallen komen later in dit hoofdstuk: een verzoek waar een browser eerst naar vraagt voordat hij het verstuurt, en een verzoek dat een meedraagt. In de volgende les schrijf je beide helften van het gewone geval, het antwoord van de server en de controle van de browser.