Otkrijte tajne CORS-a (Cross-Origin Resource Sharing) i naučite kako sigurno omogućiti zahtjeve s različitih domena u vašim web aplikacijama. Ovaj sveobuhvatni vodič pokriva sve od osnova do naprednih konfiguracija, osiguravajući besprijekornu i sigurnu komunikaciju između različitih izvora.
Demistificiranje CORS-a: Sveobuhvatan vodič za dijeljenje resursa s različitih izvora
U današnjem povezanom webu, aplikacije često trebaju pristupiti resursima s različitih izvora. Tu na scenu stupa dijeljenje resursa s različitih izvora (Cross-Origin Resource Sharing - CORS). CORS je ključni sigurnosni mehanizam koji upravlja načinom na koji web preglednici obrađuju zahtjeve s jednog izvora (domena, protokol i port) prema drugom izvoru. Razumijevanje CORS-a je neophodno za svakog web programera kako bi gradio sigurne i funkcionalne web aplikacije.
Što je pravilo istog izvora (Same-Origin Policy)?
Prije nego što zaronimo u CORS, važno je razumjeti pravilo istog izvora (Same-Origin Policy - SOP). SOP je temeljni sigurnosni mehanizam implementiran u web preglednicima. Njegova je svrha spriječiti zlonamjerne skripte na jednoj web stranici da pristupe osjetljivim podacima na drugoj web stranici. Izvor je definiran kombinacijom protokola (npr. HTTP ili HTTPS), domene (npr. example.com) i broja porta (npr. 80 ili 443). Smatra se da dva URL-a imaju isti izvor ako dijele isti protokol, domenu i port.
Primjer:
http://example.com/app1
ihttp://example.com/app2
- Isti izvor (isti protokol, domena i port)https://example.com/app1
ihttp://example.com/app1
- Različit izvor (različit protokol)http://example.com:8080/app1
ihttp://example.com/app1
- Različit izvor (različit port)http://sub.example.com/app1
ihttp://example.com/app1
- Različit izvor (različita poddomena – smatra se različitom domenom)
SOP ograničava skripte da pristupaju resursima s različitog izvora, osim ako su na snazi posebne mjere, poput CORS-a, koje to dopuštaju.
Zašto je CORS neophodan?
Iako je pravilo istog izvora ključno za sigurnost, može biti i restriktivno. Mnoge moderne web aplikacije ovise o dohvaćanju podataka s različitih poslužitelja, kao što su API-ji ili mreže za isporuku sadržaja (CDN). CORS pruža kontrolirani način za ublažavanje SOP-a i dopuštanje legitimnih zahtjeva s različitih izvora uz održavanje sigurnosti.
Razmotrimo scenarij u kojem web aplikacija smještena na http://example.com
treba dohvatiti podatke s API poslužitelja smještenog na http://api.example.net
. Bez CORS-a, preglednik bi blokirao ovaj zahtjev zbog SOP-a. CORS omogućuje API poslužitelju da eksplicitno odredi kojim je izvorima dopušten pristup njegovim resursima, omogućujući tako ispravno funkcioniranje web aplikacije.
Kako CORS funkcionira: Osnove
CORS funkcionira putem niza HTTP zaglavlja koja se razmjenjuju između klijenta (preglednika) i poslužitelja. Poslužitelj koristi ta zaglavlja kako bi obavijestio preglednik je li dopušten pristup traženom resursu. Ključno uključeno HTTP zaglavlje je Access-Control-Allow-Origin
.
Scenarij 1: Jednostavan zahtjev
"Jednostavan zahtjev" je GET, HEAD ili POST zahtjev koji zadovoljava određene kriterije (npr. Content-Type
zaglavlje je jedno od application/x-www-form-urlencoded
, multipart/form-data
ili text/plain
). U tom slučaju, preglednik šalje zahtjev izravno poslužitelju, a poslužitelj odgovara s Access-Control-Allow-Origin
zaglavljem.
Zahtjev klijenta (s http://example.com):
GET /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
Odgovor poslužitelja (s http://api.example.net):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Content-Type: application/json
{
"data": "Neki podaci s poslužitelja"
}
U ovom primjeru, poslužitelj odgovara s Access-Control-Allow-Origin: http://example.com
, što ukazuje da su zahtjevi s http://example.com
dopušteni. Ako se izvor u zahtjevu ne podudara s vrijednošću u Access-Control-Allow-Origin
zaglavlju (ili ako zaglavlje nije prisutno), preglednik će blokirati odgovor i spriječiti klijentsku skriptu da pristupi podacima.
Scenarij 2: Preflight zahtjev (za složene zahtjeve)
Za složenije zahtjeve, kao što su oni koji koriste HTTP metode poput PUT, DELETE ili oni s prilagođenim zaglavljima, preglednik izvodi "preflight" zahtjev koristeći HTTP metodu OPTIONS. Ovaj preflight zahtjev pita poslužitelj za dopuštenje prije slanja stvarnog zahtjeva. Poslužitelj odgovara sa zaglavljima koja specificiraju koje su metode, zaglavlja i izvori dopušteni.
Preflight zahtjev klijenta (s http://example.com):
OPTIONS /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Odgovor poslužitelja (s http://api.example.net):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header, Content-Type
Access-Control-Max-Age: 3600
Objašnjenje zaglavlja:
Access-Control-Allow-Origin: http://example.com
- Označava da su zahtjevi shttp://example.com
dopušteni.Access-Control-Allow-Methods: GET, PUT, DELETE
- Određuje HTTP metode dopuštene za zahtjeve s različitih izvora.Access-Control-Allow-Headers: X-Custom-Header, Content-Type
- Navodi dopuštena prilagođena zaglavlja u stvarnom zahtjevu.Access-Control-Max-Age: 3600
- Određuje trajanje (u sekundama) tijekom kojeg preglednik može predmemorirati preflight odgovor. To pomaže u smanjenju broja preflight zahtjeva.
Ako preflight odgovor poslužitelja ukazuje da je zahtjev dopušten, preglednik nastavlja sa stvarnim zahtjevom. U suprotnom, preglednik blokira zahtjev.
Stvarni zahtjev klijenta (s http://example.com):
PUT /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
X-Custom-Header: some-value
Content-Type: application/json
{
"data": "Neki podaci za ažuriranje"
}
Odgovor poslužitelja (s http://api.example.net):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Content-Type: application/json
{
"status": "Podaci uspješno ažurirani"
}
Uobičajena CORS zaglavlja
Ovdje je pregled ključnih CORS zaglavlja koja trebate razumjeti:
Access-Control-Allow-Origin
: Ovo je najosnovnije zaglavlje. Ono specificira koji su izvori dopušteni za pristup resursu. Moguće vrijednosti uključuju:- Specifičan izvor (npr.
http://example.com
). *
(džoker znak): Ovo dopušta zahtjeve s bilo kojeg izvora. Koristite s oprezom, jer može ugroziti sigurnost ako su uključeni osjetljivi podaci. Općenito bi ga trebalo izbjegavati u produkcijskim okruženjima.
- Specifičan izvor (npr.
Access-Control-Allow-Methods
: Ovo zaglavlje specificira HTTP metode (npr. GET, POST, PUT, DELETE) koje su dopuštene za zahtjeve s različitih izvora. Koristi se u preflight odgovoru.Access-Control-Allow-Headers
: Ovo zaglavlje navodi prilagođena zaglavlja koja su dopuštena u zahtjevima s različitih izvora. Također se koristi u preflight odgovoru.Access-Control-Allow-Credentials
: Ovo zaglavlje ukazuje dopušta li poslužitelj uključivanje vjerodajnica (npr. kolačića, autorizacijskih zaglavlja) u zahtjeve s različitih izvora. Trebalo bi biti postavljeno natrue
ako trebate slati vjerodajnice. Na strani klijenta, također trebate postavitiwithCredentials = true
na XMLHttpRequest objektu.Access-Control-Expose-Headers
: Prema zadanim postavkama, preglednici izlažu samo ograničen skup zaglavlja odgovora (npr.Cache-Control
,Content-Language
,Content-Type
,Expires
,Last-Modified
,Pragma
) klijentskim skriptama. Ako želite izložiti druga zaglavlja, trebate ih navesti uAccess-Control-Expose-Headers
zaglavlju.Access-Control-Max-Age
: Ovo zaglavlje specificira maksimalno vrijeme (u sekundama) tijekom kojeg preglednik može predmemorirati preflight zahtjev. Duža vrijednost smanjuje broj preflight zahtjeva, poboljšavajući performanse.
CORS u različitim poslužiteljskim jezicima
Implementacija CORS-a obično uključuje konfiguriranje vaše poslužiteljske aplikacije za slanje odgovarajućih CORS zaglavlja. Evo primjera kako to učiniti u različitim jezicima i okvirima:
Node.js s Expressom
Možete koristiti cors
middleware paket:
const express = require('express');
const cors = require('cors');
const app = express();
// Omogući CORS za sve izvore (KORISTITI S OPREZOM U PRODUKCIJI)
app.use(cors());
// Alternativno, konfigurirajte CORS za specifične izvore
// app.use(cors({
// origin: 'http://example.com'
// }));
app.get('/data', (req, res) => {
res.json({ message: 'Ovo je CORS-omogućeno za sve izvore!' });
});
app.listen(3000, () => {
console.log('Poslužitelj radi na portu 3000');
});
Python s Flaskom
Možete koristiti ekstenziju Flask-CORS
:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
# Alternativno, konfigurirajte CORS za specifične izvore
# CORS(app, resources={r"/api/*": {"origins": "http://example.com"}})
@app.route("/data")
def hello():
return {"message": "Ovo je CORS-omogućeno za sve izvore!"}
if __name__ == '__main__':
app.run(debug=True)
Java sa Spring Bootom
Možete konfigurirati CORS u vašoj Spring Boot aplikaciji koristeći anotacije ili konfiguracijske klase:
Korištenje anotacija:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Dopusti zahtjeve s http://example.com
public class DataController {
@GetMapping("/data")
public String getData() {
return "Ovo je CORS-omogućeno za http://example.com!";
}
}
Korištenje konfiguracije:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/data")
.allowedOrigins("http://example.com") // Dopusti zahtjeve s http://example.com
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}
PHP
"Ovo je CORS-omogućeno za http://example.com!");
echo json_encode($data);
?>
CORS i sigurnosna razmatranja
Iako CORS omogućuje zahtjeve s različitih izvora, ključno je implementirati ga sigurno. Evo nekoliko važnih razmatranja:
- Izbjegavajte korištenje
*
zaAccess-Control-Allow-Origin
u produkciji: Ovo dopušta zahtjeve s bilo kojeg izvora, što može biti sigurnosni rizik. Umjesto toga, eksplicitno specificirajte izvore kojima je dopušten pristup vašim resursima. - Validirajte
Origin
zaglavlje na strani poslužitelja: Čak i ako koristite okvir koji upravlja CORS konfiguracijom, dobra je praksa validiratiOrigin
zaglavlje na strani poslužitelja kako biste osigurali da zahtjev dolazi s očekivanog izvora. - Budite svjesni
Access-Control-Allow-Credentials
: Ako koristite vjerodajnice (npr. kolačiće, autorizacijska zaglavlja), pobrinite se da postaviteAccess-Control-Allow-Credentials: true
na strani poslužitelja iwithCredentials = true
na strani klijenta. Međutim, budite svjesni da korištenjeAccess-Control-Allow-Origin: *
nije dopušteno kada jeAccess-Control-Allow-Credentials
postavljeno natrue
. Morate eksplicitno specificirati dopuštene izvore. - Pravilno konfigurirajte
Access-Control-Allow-Methods
iAccess-Control-Allow-Headers
: Dopustite samo one HTTP metode i zaglavlja koja su neophodna za ispravno funkcioniranje vaše aplikacije. To pomaže u smanjenju površine napada. - Koristite HTTPS: Uvijek koristite HTTPS za svoje web aplikacije i API-je kako biste zaštitili podatke u prijenosu.
Rješavanje problema s CORS-om
Problemi s CORS-om mogu biti frustrirajući za otklanjanje. Evo nekih uobičajenih problema i kako ih riješiti:
- "No 'Access-Control-Allow-Origin' header is present on the requested resource": Ovo je najčešća CORS pogreška. Znači da poslužitelj ne šalje
Access-Control-Allow-Origin
zaglavlje u svom odgovoru. Dvaput provjerite svoju konfiguraciju na strani poslužitelja kako biste osigurali da se zaglavlje ispravno šalje. - "Response to preflight request doesn't pass access control check: It does not have HTTP ok status": Ova pogreška ukazuje da preflight zahtjev nije uspio. To se može dogoditi ako poslužitelj nije konfiguriran za rukovanje OPTIONS zahtjevima ili ako
Access-Control-Allow-Methods
iliAccess-Control-Allow-Headers
zaglavlja nisu ispravno konfigurirana. - "The value of the 'Access-Control-Allow-Origin' header in the response is not equal to the origin in the request": Ova pogreška znači da se izvor u zahtjevu ne podudara s vrijednošću u
Access-Control-Allow-Origin
zaglavlju. Pobrinite se da poslužitelj šalje ispravan izvor u odgovoru. - Predmemoriranje preglednika: Ponekad preglednici mogu predmemorirati CORS odgovore, što može dovesti do neočekivanog ponašanja. Pokušajte očistiti predmemoriju preglednika ili koristiti drugi preglednik da vidite rješava li to problem. Možete također koristiti
Access-Control-Max-Age
zaglavlje za kontrolu koliko dugo preglednik predmemorira preflight odgovor.
Alati za otklanjanje pogrešaka:
- Alati za razvojne programere u pregledniku: Koristite alate za razvojne programere u pregledniku (obično se pristupa pritiskom na F12) za pregled mrežnih zahtjeva i odgovora. Potražite zaglavlja i poruke o pogreškama vezane uz CORS.
- Online CORS provjeravači: Postoje online alati koji vam mogu pomoći testirati vašu CORS konfiguraciju. Ovi alati šalju zahtjev vašem poslužitelju i analiziraju zaglavlja odgovora kako bi identificirali potencijalne probleme.
Napredni CORS scenariji
Iako su osnovni koncepti CORS-a relativno jednostavni, postoje i neki napredniji scenariji koje treba razmotriti:
- CORS s poddomenama: Ako trebate dopustiti zahtjeve s više poddomena (npr.
app1.example.com
,app2.example.com
), ne možete jednostavno koristiti džoker znak poput*.example.com
uAccess-Control-Allow-Origin
zaglavlju. Umjesto toga, morat ćete dinamički generiratiAccess-Control-Allow-Origin
zaglavlje na temeljuOrigin
zaglavlja u zahtjevu. Ne zaboravite validirati izvor prema bijeloj listi dopuštenih poddomena kako biste spriječili sigurnosne ranjivosti. - CORS s više izvora: Ako trebate dopustiti zahtjeve s više specifičnih izvora, ne možete specificirati više izvora u
Access-Control-Allow-Origin
zaglavlju (npr.Access-Control-Allow-Origin: http://example.com, http://another.com
je nevažeće). Umjesto toga, morat ćete dinamički generiratiAccess-Control-Allow-Origin
zaglavlje na temeljuOrigin
zaglavlja u zahtjevu. - CORS i CDN-ovi: Kada koristite CDN za posluživanje vašeg API-ja, trebate konfigurirati CDN da prosljeđuje
Origin
zaglavlje vašem izvornom poslužitelju i da ispravno predmemoriraAccess-Control-Allow-Origin
zaglavlje. Konzultirajte dokumentaciju vašeg CDN pružatelja za specifične upute.
Najbolje prakse za CORS
Kako biste osigurali sigurnu i učinkovitu implementaciju CORS-a, slijedite ove najbolje prakse:
- Princip najmanjih privilegija: Dopustite samo minimalni skup izvora, metoda i zaglavlja koji su neophodni za ispravno funkcioniranje vaše aplikacije.
- Redovito pregledavajte CORS konfiguraciju: Kako se vaša aplikacija razvija, redovito pregledavajte svoju CORS konfiguraciju kako biste osigurali da je i dalje prikladna i sigurna.
- Koristite okvir ili biblioteku: Iskoristite postojeće okvire ili biblioteke koje pružaju ugrađenu podršku za CORS. To može pojednostaviti implementaciju i smanjiti rizik od pogrešaka.
- Pratite kršenja CORS-a: Implementirajte nadzor kako biste otkrili i reagirali na potencijalna kršenja CORS-a.
- Ostanite ažurirani: Budite u toku s najnovijim CORS specifikacijama i sigurnosnim preporukama.
Zaključak
CORS je ključni sigurnosni mehanizam koji omogućuje kontrolirane zahtjeve s različitih izvora u web aplikacijama. Razumijevanje kako CORS funkcionira i kako ga pravilno konfigurirati ključno je za svakog web programera. Slijedeći smjernice i najbolje prakse navedene u ovom sveobuhvatnom vodiču, možete graditi sigurne i funkcionalne web aplikacije koje besprijekorno komuniciraju s resursima s različitih izvora.
Zapamtite da uvijek dajete prednost sigurnosti i izbjegavate korištenje previše permisivnih CORS konfiguracija. Pažljivim razmatranjem sigurnosnih implikacija vaših CORS postavki, možete zaštititi svoje aplikacije i podatke od neovlaštenog pristupa.
Nadamo se da vam je ovaj vodič pomogao demistificirati CORS. Sretno kodiranje!