CORS
Vraag het voordat je verstuurt
De frontend kan /about nu lezen. Waar hij voor bedoeld is, is de boekenlijst, en GET /books heeft een token nodig:
GET /books HTTP/1.1
Host: reading.example
Origin: https://app.reading.example
Authorization: Bearer <a token>
Nog geen regel in je mini_browser.py zegt dat dit verzoek meer nodig heeft dan de GET van les 2. Een echte browser behandelt de twee verschillend. Voor dit verzoek stuurt hij eerst een ander verzoek, en deze les legt uit welk verzoek dat is en waarom.
Wat een formulier altijd al kon versturen
Denk terug aan het oude web van hoofdstuk 8, les 4. Lang voordat scripts verzoeken konden versturen, kon een pagina een formulier bevatten dat naar elke andere site postte. Zo’n formulier kan twee application/x-www-form-urlencoded, multipart/form-data of text/plain. Het kan geen eigen header toevoegen.
Servers die vóór
De grens
Een verzoek naar een andere
de methode is GET, HEAD of POST;
elke header die de pagina zette, is
Accept,Accept-Language,Content-LanguageofContent-Type, en eenContent-Typeis een van de drie formuliertypes.
Deze vier namen heten de safelist. Eén header daarbuiten is genoeg om over de grens te gaan, en elke andere methode ook.
Het volgende blok trekt de grens voor zeven verzoeken. Lees asked_first voordat je het uitvoert, en voorspel de laatste kolom.
Waarom wordt er eerst gevraagd over GET /books met een header Authorization, hoewel GET een eenvoudige methode is?
Welk van deze verzoeken naar een andere origin verstuurt een browser zonder eerst te vragen?
De standaard is fijner dan dit blok. Hij beperkt ook de lengte en de tekens van de Range met een eenvoudige waarde als safelisted, en hij laat een browser een antwoord een tijdje onthouden. Het model in deze cursus laat alle drie weg.
De vraag en het antwoord
Het verzoek dat vraagt, heet een preflight. Het is een OPTIONS-verzoek naar dezelfde GET /books van de frontend, zoals je server die aan het eind van les 4 zal beantwoorden:
OPTIONS /books HTTP/1.1
Host: reading.example
Origin: https://app.reading.example
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
HTTP/1.1 204 No Content
access-control-allow-methods: GET, HEAD, POST, PUT, DELETE
access-control-allow-headers: authorization, content-type
vary: Origin
access-control-allow-origin: https://app.reading.example
De regels Server en Date van het antwoord zijn weggelaten. De vraag noemt drie dingen: de origin van de pagina, de methode die het echte verzoek zal gebruiken, en de headers buiten de safelist die het zal meedragen. Hij noemt de headers en stuurt hun waarden niet mee.
Het antwoord zegt ja met drie eigen dingen. De status ligt tussen 200 en 299. Access-Control-Allow-Origin noemt de origin van de pagina. En de twee Access-Control-Allow-Methods, tenzij het GET, HEAD of POST is, die niet vermeld hoeven te worden, en elke gevraagde header staat in Access-Control-Allow-Headers.
the page the browser the server
1. asks for GET /books
with a token ---->
2. OPTIONS /books: may this origin send
GET with authorization?
--------------->
3. 204, the origin,
the two lists
<---------------
4. the answer fits: GET /books
with the token
--------------->
5. 200, the list,
the origin again
<---------------
<--------------- 6. hands the response to the script
Deze keer zes stappen. De pagina vraagt. De browser stuurt de preflight. De server beantwoordt die. Als het antwoord past, stuurt de browser het echte verzoek, en als het niet past, stopt de browser en vertrekt het echte verzoek nooit. De server beantwoordt het echte verzoek nog een keer met Access-Control-Allow-Origin, en de browser past de controle van les 2 toe op dat antwoord.
Eén detail bepaalt hoe je de server schrijft. De preflight draagt geen Authorization. Hij vraagt of een verzoek überhaupt verstuurd mag worden, en de server moet kunnen antwoorden zonder te weten wie het vraagt.
Een server beantwoordt OPTIONS /books met 401, omdat er geen token meekwam. Wat gebeurt er met het echte verzoek van de frontend?
Je server is vandaag die server. Zijn boekroutes controleren het token vóór al het andere, dus OPTIONS /books krijgt een 401.
Waarom dit oude servers beschermt en de jouwe niet
Een preflight is de browser die voorzichtig is namens een server die nog nooit van CORS heeft gehoord. Zo’n server beantwoordt de vraag niet, dus een pagina op een andere origin kan hem alleen sturen wat een formulier altijd al kon versturen.
De voorzichtigheid houdt op bij de grens. Over een eenvoudig verzoek wordt nooit gevraagd, en precies daar maakte hoofdstuk 8 gebruik van: de vervalste delete was een formulier-post. Een server kan ook per ongeluk een van zijn eigen routes over de grens schuiven. Een route die text/plain, accepteert een verzoek dat elke browser zonder vragen verstuurt. Je verwijderformulier weigert sinds hoofdstuk 7 elk content type behalve het eigen type, en de boekroutes accepteren JSON alleen onder application/json.