Üdvözöljük a webfejlesztés egyik leggyakoribb, mégis gyakran félreértett kihívásának, a CORS (Cross-Origin Resource Sharing) hibáknak a világában! Ha valaha is találkozott már azzal a frusztráló böngészőkonzol üzenettel, ami így kezdődik: „Access to XMLHttpRequest at ‘…’ from origin ‘…’ has been blocked by CORS policy…”, akkor tudja, milyen mélyrehatóan képes lelassítani egy projektet. Ez a cikk azért született, hogy alaposan megvilágítsa a CORS mechanizmusát, segítve Önt abban, hogy ne csak orvosolja, hanem alapjaiban értse és megelőzze ezeket a hibákat REST API fejlesztése során.
Mi az a CORS és miért van rá szükség?
A CORS, vagyis a Cross-Origin Resource Sharing, egy olyan HTTP alapú biztonsági mechanizmus, amely lehetővé teszi egy weboldal számára, hogy erőforrásokat kérjen egy másik domainről, protokollból vagy portról (azaz egy „cross-origin” kérést indítson). De miért van erre szükség, és miért nem engedélyezettek alapból ezek a kérések?
A válasz a web biztonságának alapkövében, az úgynevezett Same-Origin Policy-ban (SOP) rejlik. A SOP egy kritikus biztonsági szabály, amelyet minden modern böngésző implementál. Ez kimondja, hogy egy weboldalon futó szkript csak az ugyanazon az „origin”-ről származó erőforrásokhoz férhet hozzá. Egy „origin” a protokoll (pl. http
, https
), a host (domain név, pl. example.com
) és a port (pl. 80
, 443
) hármasából tevődik össze. Ha a kérés ezen paraméterek bármelyikében eltér a forrásoldaltól, a böngésző ezt cross-origin kérésnek tekinti, és alapértelmezés szerint letiltja azt.
A SOP célja, hogy megakadályozza a rosszindulatú weboldalakat abban, hogy jogosulatlanul olvassák egy másik weboldal adatait. Képzelje el, mi történne, ha egy rosszindulatú oldal beágyazhatná az Ön online bankjának oldalát, majd az oldalon futó JavaScript kóddal hozzáférhetne az Ön számlaegyenlegéhez! A SOP megakadályozza ezt a típusú támadást.
Azonban a modern webalkalmazások gyakran igénylik, hogy erőforrásokat töltsenek be más forrásokból. Gondoljon csak a különböző szolgáltatók (pl. térképszolgáltatások, fizetési átjárók, vagy akár a saját frontendjétől elkülönített REST API-k) adataira. Ezekre az esetekre nyújt megoldást a CORS. A CORS egy kontrollált, biztonságos módszert biztosít a SOP megkerülésére, lehetővé téve a szervernek, hogy explicit módon engedélyezze bizonyos cross-origin kéréseket.
Hogyan működik a CORS? A színfalak mögött
A CORS működésének megértéséhez kulcsfontosságú, hogy megismerjük a böngésző és a szerver közötti kommunikációt, különösen az HTTP fejlécek szerepét. A CORS kérések két fő kategóriába sorolhatók: egyszerű kérések (Simple Requests) és előzetes ellenőrző kérések (Preflight Requests).
Egyszerű kérések (Simple Requests)
Egy kérés akkor minősül egyszerűnek, ha megfelel bizonyos feltételeknek:
- A HTTP metódus csak
GET
,HEAD
vagyPOST
lehet. - A HTTP fejléceken kívül csak bizonyos automatikusan beállított fejlécek (pl.
Accept
,Accept-Language
,Content-Language
,Content-Type
) és aContent-Type
esetén csak aapplication/x-www-form-urlencoded
,multipart/form-data
vagytext/plain
értékek használhatók.
Ha egy kérés egyszerűnek minősül, a böngésző egyből elküldi azt a cél szervernek. A kéréshez hozzáadja az Origin
HTTP fejlécet, amely tartalmazza a kérést indító weboldal origin-jét (pl. http://localhost:3000
). A szerver, miután feldolgozta a kérést, válaszol. Ha a szerver engedélyezi a cross-origin hozzáférést erről az originről, akkor a válaszban szerepelnie kell az Access-Control-Allow-Origin
HTTP fejlécenek, amely megegyezik a kérés Origin
fejlécével, vagy egy *
(wildcard) karakterrel, ami minden origint engedélyez. Ha ez a fejléc hiányzik, vagy nem egyezik meg, a böngésző letiltja a választ, és CORS hibát jelez.
Előzetes ellenőrző kérések (Preflight Requests)
Ha egy kérés nem minősül egyszerűnek (pl. PUT
, DELETE
metódusokat használ, vagy egyéni fejléceket tartalmaz, vagy a Content-Type
más, mint a fent említettek), a böngésző a tényleges kérés elküldése előtt egy előzetes ellenőrző kérést (preflight request) küld a szervernek. Ez egy OPTIONS
metódusú kérés, amely arra szolgál, hogy megtudja, a szerver hajlandó-e elfogadni a tényleges kérést.
Az OPTIONS
kérés tartalmazza az Origin
fejléce mellett az Access-Control-Request-Method
(a tényleges kérés metódusa) és az Access-Control-Request-Headers
(a tényleges kérésben használt egyéni fejlécek) fejléceket. A szervernek erre az OPTIONS
kérésre is válaszolnia kell, és a válaszában jeleznie kell, hogy engedélyezi-e a szóban forgó metódust, fejléceket és origint.
A válaszban szerepelő fontos CORS fejlécek:
Access-Control-Allow-Origin
: Meghatározza, mely origin-ek férhetnek hozzá az erőforráshoz. Lehet egy konkrét origin (pl.http://example.com
), több vesszővel elválasztott origin (bár ez ritkább, inkább a szerver oldali logikával megoldott), vagy*
(bármilyen origin).Access-Control-Allow-Methods
: Felsorolja azokat a HTTP metódusokat (pl.GET, POST, PUT, DELETE
), amelyeket a szerver engedélyez.Access-Control-Allow-Headers
: Felsorolja azokat a HTTP fejléceket, amelyeket a szerver elfogad a tényleges kérésben.Access-Control-Max-Age
: Megadja, hogy az előzetes ellenőrző kérés válaszát mennyi ideig tárolja a böngésző a gyorsítótárában másodpercekben. Ez csökkentheti azOPTIONS
kérések számát.Access-Control-Allow-Credentials
: Jelzi, hogy a szerver elfogadja-e a hitelesítő adatokat (pl. sütik, HTTP hitelesítés, TLS kliens tanúsítványok) a cross-origin kérések során. Ha ez a fejléctrue
, akkor azAccess-Control-Allow-Origin
nem lehet*
, hanem egy konkrét origint kell megadnia.Access-Control-Expose-Headers
: Néhány válasz fejlécet a böngésző alapértelmezés szerint nem tesz elérhetővé a kliensoldali JavaScript számára cross-origin kéréseknél. Ezzel a fejlécet lehetőség van további fejlécek elérhetővé tételére.
Csak ha az OPTIONS
kérés sikeres, és a szerver válasza alapján a böngésző meggyőződött arról, hogy a tényleges kérés biztonságosan elküldhető, akkor küldi el a tényleges HTTP kérést.
Gyakori CORS hibák és felismerésük
A CORS hibák szinte mindig a böngésző konzoljában jelennek meg, és általában elég informatívak. Íme néhány tipikus üzenet és okuk:
Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Ez a leggyakoribb hiba. A szerver nem küldte el azAccess-Control-Allow-Origin
fejléceket, vagy ha el is küldte, az nem tartalmazta a kérést indító origin-t.Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin.
A szerver küldöttAccess-Control-Allow-Origin
fejlécet, de az értéke nem egyezik meg a kérésOrigin
fejlécével.Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: Method 'PUT' is not allowed by Access-Control-Allow-Methods in preflight response.
Ez egy preflight request hiba. A szerver válasza azOPTIONS
kérésre nem tartalmazza aPUT
metódust azAccess-Control-Allow-Methods
fejléceben.Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: Request header field X-Custom-Header is not allowed by Access-Control-Allow-Headers in preflight response.
A kérés egyéni fejléce (X-Custom-Header
) nem szerepel a szerverAccess-Control-Allow-Headers
fejléceben az OPTIONS válaszban.Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
A kliensoldali kérés hitelesítő adatokat is küld (pl.withCredentials: true
), de a szerver válasza nem tartalmazza azAccess-Control-Allow-Credentials: true
fejléceket.
A CORS hibák megoldása: Átfogó útmutató
A CORS hibák megoldása szinte mindig a szerveroldali beállításokban rejlik. A böngésző helyesen hajtja végre a Same-Origin Policy-t és a CORS szabályokat; a hiba oka az, hogy az API szerver nem kommunikálja vissza megfelelően az engedélyeket.
1. Szerveroldali konfiguráció
A legfontosabb lépés a REST API-t kiszolgáló szerver konfigurálása, hogy megfelelő CORS fejléceket küldjön a válaszokban.
A. Az Access-Control-Allow-Origin
beállítása
- Specifikus Origin engedélyezése: Ez a legbiztonságosabb megoldás. Csak azokat az origin-eket engedélyezze, amelyek valóban igénylik a hozzáférést.
Access-Control-Allow-Origin: http://yourfrontend.com
Ha több origint kell engedélyeznie, akkor a szerveroldali logika alapján kell ellenőriznie a kérésOrigin
fejléceit, majd dinamikusan beállítania azAccess-Control-Allow-Origin
fejléceit a kérésOrigin
értékére, ha az szerepel az engedélyezett listán. - Wildcard
*
(Minden Origin engedélyezése): Fejlesztői környezetben vagy nyilvános, autentikációt nem igénylő API-k esetén néha használható, de éles környezetben (production) kerülendő a biztonsági kockázatok miatt.
Access-Control-Allow-Origin: *
Fontos megjegyezni, hogy az*
és azAccess-Control-Allow-Credentials: true
nem használhatók együtt.
B. Az OPTIONS
kérések kezelése (Preflight Requests)
Azoknál a kéréseknél, amelyek preflight request-et váltanak ki, a szervernek megfelelően kell válaszolnia az OPTIONS
metódusra. Ennek a válasznak tartalmaznia kell az engedélyezett metódusokat és fejléceket.
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With, ...
(ide minden egyéni fejlécet fel kell sorolni, amit a kliens küldeni fog)Access-Control-Max-Age: 86400
(1 nap, a böngésző ennyi ideig gyorsítótárazza a preflight válaszokat)
Sok webes keretrendszer (pl. Express.js a Node.js-ben, Spring Boot a Java-ban, Flask a Pythonban) rendelkezik beépített CORS middleware-rel vagy konfigurációs lehetőségekkel, amelyek leegyszerűsítik ezeket a beállításokat. Például Express.js esetén a cors
npm csomag használata:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'http://yourfrontend.com', // Vagy egy lista: ['http://f1.com', 'http://f2.com']
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true // Ha hitelesítő adatokkal dolgozunk
}));
// ... további API végpontok
C. Hitelesítő adatok kezelése (Access-Control-Allow-Credentials
)
Ha a kliensoldali kérés sütiket, HTTP hitelesítést vagy SSL tanúsítványokat is küld cross-origin módon (pl. fetch('...', { credentials: 'include' })
vagy axios.get('...', { withCredentials: true })
), akkor a szerver válaszának tartalmaznia kell az Access-Control-Allow-Credentials: true
fejléceket is. Ne feledje, ilyenkor az Access-Control-Allow-Origin
nem lehet *
.
2. Kliensoldali szempontok
Bár a megoldás elsősorban a szerver oldalon van, a kliensoldalon is oda kell figyelni néhány dologra, főleg a hitelesítő adatokkal kapcsolatban. Győződjön meg róla, hogy ha hitelesítő adatokat (sütiket, autorizációs tokent) küld cross-origin kérés során, akkor ezt explicit módon jelezze a böngészőnek.
// Fetch API esetén
fetch('http://your-api.com/data', {
method: 'GET',
credentials: 'include' // Ez elküldi a sütiket is
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
// Axios esetén
axios.get('http://your-api.com/data', {
withCredentials: true // Ez elküldi a sütiket is
})
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
3. Fejlesztői környezeti megoldások
Fejlesztés során néha szükség van gyors és átmeneti megoldásokra a CORS hibák áthidalására, mielőtt a végleges szerveroldali konfiguráció elkészülne.
A. Proxy szerverek
Ez a legajánlottabb módszer fejlesztés során. Egy proxy szerver lehetővé teszi, hogy a frontend alkalmazása a saját origin-jén belülről hívja meg a backend API-ját. A proxy szerver továbbítja a kérést a tényleges backendnek, és a választ is ő küldi vissza a frontendnek, de mindezt úgy, mintha egy „same-origin” kérés lenne.
Például egy React alkalmazásban, amely a create-react-app
-pal készült, a package.json
fájlba beírható a "proxy": "http://localhost:5000"
(ahol a 5000 a backend portja). Ekkor a /api/users
hívások automatikusan a proxy-n keresztül mennek a http://localhost:5000/api/users
címre.
Hasonlóképpen, a Vite, Webpack dev server, vagy akár egy egyszerű Node.js proxy is használható erre a célra.
B. Böngésző kiterjesztések (csak fejlesztésre!)
Vannak olyan böngésző kiterjesztések, amelyek átmenetileg letiltják a CORS-t, vagy beállítják az Access-Control-Allow-Origin: *
fejléceket. Ezeket szigorúan csak fejlesztésre és hibakeresésre használja, soha ne támaszkodjon rájuk éles környezetben, és lehetőleg ne is tartsa bekapcsolva őket állandóan a böngészőjében, mivel súlyos biztonsági kockázatot jelentenek.
4. Alternatívák és haladó technikák
A. Reverse Proxy (Nginx, Apache)
Éles környezetben gyakori megoldás egy reverse proxy (pl. Nginx vagy Apache) használata. A reverse proxy a frontend és a backend között helyezkedik el, és kezeli a kéréseket. Konfigurálható úgy, hogy hozzáadja a szükséges CORS fejléceket a backend válaszaihoz, vagy akár átírja az origin-t, így a frontend és a backend is ugyanazon az origin-en keresztül érhető el a kliens számára. Ez egy tiszta és hatékony megoldás, amely elválasztja a CORS logikát a backend alkalmazástól.
# Nginx konfiguráció példa
location /api/ {
add_header 'Access-Control-Allow-Origin' 'http://yourfrontend.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://your_backend_server:8080/;
}
B. JSONP (legacy)
A JSONP (JSON with Padding) egy régebbi technika, amelyet a CORS bevezetése előtt használtak cross-domain kérésekre. Működése azon alapul, hogy a <script>
tagekre nem vonatkozik a Same-Origin Policy. Egy JSONP kérés gyakorlatilag egy script betöltés, ami egy callback függvényt hív meg a szerverről kapott adattal. Ma már nem ajánlott, mivel biztonsági kockázatokat hordoz, és csak GET
kérésekre korlátozódik. A CORS sokkal rugalmasabb és biztonságosabb megoldás.
Biztonsági megfontolások és legjobb gyakorlatok
A CORS nem csupán egy technikai akadály, hanem egy fontos biztonsági mechanizmus. Ennek fényében néhány legjobb gyakorlatot érdemes szem előtt tartani:
- A legszűkebb origin lista: Mindig csak azokat az origin-eket engedélyezze, amelyekre valóban szükség van. Soha ne használja az
Access-Control-Allow-Origin: *
beállítást éles környezetben, ha a REST API privát adatokat kezel, vagy hitelesítést igényel. - Soha ne tegye hozzáférhetővé a bizalmas adatokat
*
wildcard mellett: Ez egy nyilvánvaló biztonsági rés, amely lehetővé tenné bármely rosszindulatú oldal számára, hogy hozzáférjen az Ön felhasználóinak adataihoz. - Gondosan kezelje a hitelesítő adatokat: Ha az
Access-Control-Allow-Credentials: true
beállítást használja, győződjön meg róla, hogy azAccess-Control-Allow-Origin
explicit módon van beállítva, és soha nem*
. - Fejlécek szűrése: Csak azokat az
Access-Control-Allow-Headers
-et engedélyezze, amelyekre a kliensoldalnak valóban szüksége van. Minél kevesebb, annál jobb. - Folyamatos tesztelés: A CORS beállítások megváltoztatása után mindig alaposan tesztelje az API-t a különböző kliensoldalakról, hogy megbizonyosodjon a megfelelő működésről és a biztonságról.
Összegzés
A CORS hibák kezdetben félelmetesnek tűnhetnek, de a mögöttes mechanizmusok megértésével és a helyes szerveroldali konfigurációval könnyedén kezelhetők. A CORS nem egy akadály, hanem egy alapvető biztonsági funkció, amely segít megvédeni a felhasználókat és az alkalmazásokat a rosszindulatú támadásoktól. Azáltal, hogy megérti az HTTP fejlécek szerepét, az egyszerű kérések és a preflight kérések közötti különbséget, és alkalmazza a legjobb gyakorlatokat, hatékonyan oldhatja meg és előzheti meg a CORS problémákat, hozzájárulva ezzel robusztusabb és biztonságosabb REST API-k és webalkalmazások építéséhez. Ne feledje, a kulcs a megfelelő kommunikáció a böngésző és az API szerver között – tegye egyértelművé, hogy mely origin-ek, metódusok és fejlécek számára engedélyezett a hozzáférés, és a böngésző boldogan engedi a forgalmat!
Leave a Reply