A lecke végére meg tudod mondani, mikor azonos két URL eredete, mit korlátoz és mit enged a same-origin policy, hogyan működik a CORS és a preflight, és miért nem hozzáférés-védelem a CORS.
Miért kell elkülöníteni az oldalakat?
A hallgató egyszerre megnyitja a Kurzuspontot és egy idegen weboldalt. Ha az idegen oldal JavaScriptje akármit kérhetne a Kurzuspont nevében, és elolvashatná a választ, a bejelentkezett hallgató személyes adatai a támadó kezébe kerülnének: a böngésző ugyanis a cookie-t is csatolná. A böngésző ezért szabályt tart fenn: a különböző eredetű oldalak egymás adatait alapesetben nem olvashatják. Ez a same-origin policy (azonos eredet elve).
Mit jelent az eredet?
Az eredet (origin) a séma, a hosztnév és a port együttese. Az MDN példája szerint a http://store.company.com/dir/page.html címhez viszonyítva:
Másik URL
Azonos eredet?
Miért?
http://store.company.com/dir2/other.html
igen
csak az útvonal különbözik
https://store.company.com/page.html
nem
más a séma
http://store.company.com:81/dir/page.html
nem
más a port (a http alapértelmezett portja 80)
http://news.company.com/dir/page.html
nem
más a hosztnév
Az útvonal tehát nem része az eredetnek. (A cookie-k az MDN szerint más tartomány- és útvonal-alapú értelmezést követnek, nem az eredetet.) Hasonlóan eredetenként különülnek el a localStorage és az IndexedDB tartalmai is (3.6).
flowchart LR
A[kurzuspont.example oldala] -->|azonos eredet| P[kurzuspont.example API]
A -.->|kereszt-eredet: CORS kell az olvasáshoz| Q[api.kurzuspont.example]
X[idegen.example oldala] -.->|olvasás korlátozott| P
Mit korlátoz és mit enged?
Az MDN összefoglalója szerint:
Tiltott (alapesetben): egy oldal szkriptje nem olvashatja egy másik eredet válaszát (fetch() válasz), és nem fér hozzá a másik eredet tárolt adataihoz.
Megengedett:kereszt-eredetű írás (hivatkozások, átirányítások, űrlapok elküldése), valamint beágyazás (<script src>, <img>, <iframe>, stílusok), amelyek során a böngésző kérést küld, de a szkript nem olvashatja az eredményt.
Ez nagyon fontos különbség: a same-origin policy nem azt mondja, hogy a böngészőből nem indulhat kérés más eredet felé. Azt mondja, hogy a küldő oldal JavaScriptje általában nem olvashatja a választ. A szerver ettől még megkaphatja a kérést, és akár mellékhatás is történhet (8.4).
Mit tesz a CORS?
A CORS (kereszt-eredetű erőforrás-megosztás) HTTP-fejlécekkel működő mechanizmus, amellyel a szerver megmondhatja, mely más eredetek tölthetik be az erőforrásait, illetve olvashatják a válaszát a böngészőben. Működés:
A böngésző a kereszt-eredetű kérésben Origin fejlécet küld.
A szerver az Access-Control-Allow-Origin válaszfejlécben megnevezi az engedélyezett eredetet.
Ha a válasz engedélyezi a kérő eredetét, a böngésző átadja a választ a szkriptnek; ha nem, blokkolja.
Kipróbálva egy kipróbáló szerverrel, amely csak a https://kurzuspont.example eredetet engedélyezi:
A második kérésre a szerver ugyanúgy válaszolt (200, törzzsel), csak az Access-Control-Allow-Origin fejléc hiányzik. A böngésző emiatt nem adná át a választ az idegen oldal szkriptjének. A curl viszont nem böngésző: nem érvényesíti a CORS-t, ezért ugyanazt a törzset látja. A CORS tehát böngészős olvasási korlát, nem hozzáférés-védelem.
A Vary: Origin jelzi a gyorsítótáraknak, hogy a válasz az Origin értékétől függ (az MDN javasolja dinamikus eredetnél).
Preflight
Az MDN szerint egyszerű kérés az, amely GET, HEAD vagy POST metódusú, csak biztonságosnak minősített fejléceket használ, és a Content-Type értéke application/x-www-form-urlencoded, multipart/form-data vagy text/plain. A többi (például Content-Type: application/json vagy egyedi fejléc) esetén a böngésző előbb egy preflightOPTIONS kérést küld, és csak az engedélyek alapján folytatja a tényleges kérést.
sequenceDiagram
participant B as Böngésző
participant A as API
B->>A: OPTIONS + Origin + tervezett metódus és fejléc
A-->>B: Engedélyezett eredet, metódus, fejlécek
B->>A: Tényleges API-kérés
A-->>B: Válasz + CORS-fejlécek
Az Access-Control-Max-Age megmondja, mennyi ideig tárolható a preflight eredménye (az MDN szerint alapértelmezés szerint 5 másodperc). Ha az idegen eredetre a preflight nem ad engedélyt (a fenti szerver ilyenkor üres 204 választ ad, Access-Control-Allow-* nélkül), a böngésző a tényleges kérést el sem küldi.
Cookie-k és a csillag
Alapértelmezés szerint a kereszt-eredetű kérések nem küldenek hitelesítő adatot (cookie-t). Ha mégis szükséges, a kliensnek ezt kérnie kell (credentials: "include"), a szervernek pedig Access-Control-Allow-Credentials: true választ kell adnia. Az MDN szerint ilyenkor a * helyettesítő érték nem használható az Access-Control-Allow-Origin fejlécben: kifejezett eredetet kell megadni. A cookie-k saját SameSite szabályai ettől külön réteget alkotnak (7.2).
Mire nem való a CORS?
Gyakori hiba, hogy a fejlesztők a CORS-hibát „megoldják” egy * eredet beállításával. Ez csak a böngészős olvasási korlátot oldja fel mindenkinek; ha a válasz személyes adatot tartalmaz, a hozzáférés-védelmet nem a CORS-nak kell adnia.
Végigvezetett példa: a Kurzuspont külön API-tartománya
A Kurzuspont felülete a https://kurzuspont.example címen fut, az API a https://api.kurzuspont.example címen. A két cím eltérő hosztnév, tehát eltérő eredet.
Helyzet
Mi történik?
A felület JSON-t kér az API-tól
Preflight (JSON Content-Type), amelyre az API engedélyezi a https://kurzuspont.example eredetet.
Egy idegen oldal ugyanezt kérné
A preflightra nem kap engedélyt, a böngésző nem küldi el a tényleges kérést.
A felület cookie-t is küldene
credentials: "include", az API pontos eredetet és Allow-Credentials: true fejlécet ad.
Egy szkript curl-lel hívja az API-t
A CORS nem érvényesül; az API-nak hitelesítéssel és jogosultsággal kell védekeznie.
Gyakori tévhitek
Állítás
Pontosítás
„A CORS megvédi az API-t a nem kívánt kliensektől.”
A böngészőben a válasz olvasását szabályozza; szerveroldali hozzáférésvédelem is kell.
„Másik útvonal már másik eredet.”
Az útvonal nem része az eredetnek.
„A CORS-hiba azt jelenti, hogy a kérés nem ment el.”
Egyszerű kérésnél a kérés elmehet, csak a válasz nem olvasható.
„Minden kereszt-eredetű kérés előtt van OPTIONS.”
Csak a nem egyszerű kérések előtt.
„A * mindig jó megoldás.”
Cookie-s kérésnél nem használható, és személyes adatnál veszélyes.
Röviden
Az eredet = séma + hosztnév + port; az útvonal nem része.
A same-origin policy a kereszt-eredetű olvasást korlátozza, az írást és a beágyazást engedi.
A CORS a szerver Access-Control-* fejléceivel engedélyez kereszt-eredetű olvasást; nem egyszerű kérés előtt preflight van.
A CORS böngészős mechanizmus: curl-re nem hat, jogosultság-ellenőrzést nem pótol.
Ellenőrző kérdések
Azonos eredetű-e a https://kurzuspont.example és a https://kurzuspont.example:8443?
Mit enged és mit tilt a same-origin policy?
Mikor küld a böngésző preflight kérést?
Miért nem védi az API-t a CORS egy közvetlenül futtatott szkripttel szemben?
Same-origin policy és CORS
Célok
A lecke végére meg tudod mondani, mikor azonos két URL eredete, mit korlátoz és mit enged a same-origin policy, hogyan működik a CORS és a preflight, és miért nem hozzáférés-védelem a CORS.
Miért kell elkülöníteni az oldalakat?
A hallgató egyszerre megnyitja a Kurzuspontot és egy idegen weboldalt. Ha az idegen oldal JavaScriptje akármit kérhetne a Kurzuspont nevében, és elolvashatná a választ, a bejelentkezett hallgató személyes adatai a támadó kezébe kerülnének: a böngésző ugyanis a cookie-t is csatolná. A böngésző ezért szabályt tart fenn: a különböző eredetű oldalak egymás adatait alapesetben nem olvashatják. Ez a same-origin policy (azonos eredet elve).
Mit jelent az eredet?
Az eredet (origin) a séma, a hosztnév és a port együttese. Az MDN példája szerint a
http://store.company.com/dir/page.htmlcímhez viszonyítva:http://store.company.com/dir2/other.htmlhttps://store.company.com/page.htmlhttp://store.company.com:81/dir/page.htmlhttpalapértelmezett portja 80)http://news.company.com/dir/page.htmlAz útvonal tehát nem része az eredetnek. (A cookie-k az MDN szerint más tartomány- és útvonal-alapú értelmezést követnek, nem az eredetet.) Hasonlóan eredetenként különülnek el a
localStorageés az IndexedDB tartalmai is (3.6).flowchart LR A[kurzuspont.example oldala] -->|azonos eredet| P[kurzuspont.example API] A -.->|kereszt-eredet: CORS kell az olvasáshoz| Q[api.kurzuspont.example] X[idegen.example oldala] -.->|olvasás korlátozott| PMit korlátoz és mit enged?
Az MDN összefoglalója szerint:
fetch()válasz), és nem fér hozzá a másik eredet tárolt adataihoz.<script src>,<img>,<iframe>, stílusok), amelyek során a böngésző kérést küld, de a szkript nem olvashatja az eredményt.Ez nagyon fontos különbség: a same-origin policy nem azt mondja, hogy a böngészőből nem indulhat kérés más eredet felé. Azt mondja, hogy a küldő oldal JavaScriptje általában nem olvashatja a választ. A szerver ettől még megkaphatja a kérést, és akár mellékhatás is történhet (8.4).
Mit tesz a CORS?
A CORS (kereszt-eredetű erőforrás-megosztás) HTTP-fejlécekkel működő mechanizmus, amellyel a szerver megmondhatja, mely más eredetek tölthetik be az erőforrásait, illetve olvashatják a válaszát a böngészőben. Működés:
Originfejlécet küld.Access-Control-Allow-Originválaszfejlécben megnevezi az engedélyezett eredetet.Kipróbálva egy kipróbáló szerverrel, amely csak a
https://kurzuspont.exampleeredetet engedélyezi:A második kérésre a szerver ugyanúgy válaszolt (200, törzzsel), csak az
Access-Control-Allow-Originfejléc hiányzik. A böngésző emiatt nem adná át a választ az idegen oldal szkriptjének. Acurlviszont nem böngésző: nem érvényesíti a CORS-t, ezért ugyanazt a törzset látja. A CORS tehát böngészős olvasási korlát, nem hozzáférés-védelem.A
Vary: Originjelzi a gyorsítótáraknak, hogy a válasz azOriginértékétől függ (az MDN javasolja dinamikus eredetnél).Preflight
Az MDN szerint egyszerű kérés az, amely
GET,HEADvagyPOSTmetódusú, csak biztonságosnak minősített fejléceket használ, és aContent-Typeértékeapplication/x-www-form-urlencoded,multipart/form-datavagytext/plain. A többi (példáulContent-Type: application/jsonvagy egyedi fejléc) esetén a böngésző előbb egy preflightOPTIONSkérést küld, és csak az engedélyek alapján folytatja a tényleges kérést.sequenceDiagram participant B as Böngésző participant A as API B->>A: OPTIONS + Origin + tervezett metódus és fejléc A-->>B: Engedélyezett eredet, metódus, fejlécek B->>A: Tényleges API-kérés A-->>B: Válasz + CORS-fejlécekAz
Access-Control-Max-Agemegmondja, mennyi ideig tárolható a preflight eredménye (az MDN szerint alapértelmezés szerint 5 másodperc). Ha az idegen eredetre a preflight nem ad engedélyt (a fenti szerver ilyenkor üres204választ ad,Access-Control-Allow-*nélkül), a böngésző a tényleges kérést el sem küldi.Cookie-k és a csillag
Alapértelmezés szerint a kereszt-eredetű kérések nem küldenek hitelesítő adatot (cookie-t). Ha mégis szükséges, a kliensnek ezt kérnie kell (
credentials: "include"), a szervernek pedigAccess-Control-Allow-Credentials: trueválaszt kell adnia. Az MDN szerint ilyenkor a*helyettesítő érték nem használható azAccess-Control-Allow-Originfejlécben: kifejezett eredetet kell megadni. A cookie-k sajátSameSiteszabályai ettől külön réteget alkotnak (7.2).Mire nem való a CORS?
Gyakori hiba, hogy a fejlesztők a CORS-hibát „megoldják” egy
*eredet beállításával. Ez csak a böngészős olvasási korlátot oldja fel mindenkinek; ha a válasz személyes adatot tartalmaz, a hozzáférés-védelmet nem a CORS-nak kell adnia.Végigvezetett példa: a Kurzuspont külön API-tartománya
A Kurzuspont felülete a
https://kurzuspont.examplecímen fut, az API ahttps://api.kurzuspont.examplecímen. A két cím eltérő hosztnév, tehát eltérő eredet.Content-Type), amelyre az API engedélyezi ahttps://kurzuspont.exampleeredetet.credentials: "include", az API pontos eredetet ésAllow-Credentials: truefejlécet ad.curl-lel hívja az API-tGyakori tévhitek
OPTIONS.”*mindig jó megoldás.”Röviden
Access-Control-*fejléceivel engedélyez kereszt-eredetű olvasást; nem egyszerű kérés előtt preflight van.curl-re nem hat, jogosultság-ellenőrzést nem pótol.Ellenőrző kérdések
https://kurzuspont.exampleés ahttps://kurzuspont.example:8443?Tanulási források