Sveobuhvatan vodič za poboljšanje sigurnosti frontenda korištenjem Politike sigurnosti sadržaja (CSP) i Cross-Origin Resource Sharing (CORS-a), štiteći vaše web aplikacije od modernih prijetnji.
Jačanje sigurnosti frontenda: Politika sigurnosti sadržaja (CSP) i CORS
U današnjem međusobno povezanom digitalnom okruženju, sigurnost frontenda je od iznimne važnosti. Web aplikacije su sve češće meta sofisticiranih napada, što čini robusne sigurnosne mjere nužnima. Dvije ključne komponente sigurne frontend arhitekture su Politika sigurnosti sadržaja (CSP) i Cross-Origin Resource Sharing (CORS). Ovaj sveobuhvatan vodič pruža detaljan uvid u ove tehnologije, nudeći praktične primjere i korisne savjete kako biste ojačali svoje web aplikacije protiv modernih prijetnji.
Što je Politika sigurnosti sadržaja (CSP)?
Politika sigurnosti sadržaja (CSP) je dodatni sloj sigurnosti koji pomaže u otkrivanju i ublažavanju određenih vrsta napada, uključujući Cross-Site Scripting (XSS) i napade ubacivanjem podataka (data injection). CSP se implementira tako da web poslužitelj šalje pregledniku HTTP zaglavlje odgovora Content-Security-Policy. Ovo zaglavlje definira bijelu listu izvora s kojih preglednik smije učitavati resurse. Ograničavanjem izvora sadržaja koje preglednik može učitati, CSP znatno otežava napadačima ubacivanje zlonamjernog koda na vašu web stranicu.
Kako CSP radi
CSP radi tako da nalaže pregledniku da učitava resurse (npr. skripte, stilove, slike, fontove) samo s odobrenih izvora. Ti su izvori navedeni u CSP zaglavlju pomoću direktiva. Ako preglednik pokuša učitati resurs s izvora koji nije izričito dopušten, blokirat će zahtjev i prijaviti kršenje.
CSP direktive: Sveobuhvatan pregled
CSP direktive kontroliraju vrste resursa koji se mogu učitavati s određenih izvora. Slijedi pregled nekih od najvažnijih direktiva:
- default-src: Određuje zadani izvor za sve vrste sadržaja. Ovo je rezervna direktiva koja se primjenjuje kada druge, specifičnije direktive nisu prisutne.
- script-src: Određuje izvore s kojih se skripte mogu učitavati. Ovo je ključno za sprječavanje XSS napada.
- style-src: Određuje izvore s kojih se stilovi (stylesheets) mogu učitavati.
- img-src: Određuje izvore s kojih se slike mogu učitavati.
- font-src: Određuje izvore s kojih se fontovi mogu učitavati.
- media-src: Određuje izvore s kojih se audio i video mogu učitavati.
- object-src: Određuje izvore s kojih se dodaci (npr. Flash) mogu učitavati. Često se postavlja na 'none' kako bi se dodaci u potpunosti onemogućili zbog njihovih inherentnih sigurnosnih rizika.
- frame-src: Određuje izvore s kojih se okviri (npr. <iframe>) mogu učitavati.
- connect-src: Određuje URL-ove na koje se korisnički agent može povezati koristeći skriptna sučelja kao što su XMLHttpRequest, WebSocket i EventSource.
- base-uri: Određuje URL-ove koji se mogu koristiti u <base> elementu dokumenta.
- form-action: Određuje URL-ove na koje se mogu slati podaci iz obrazaca.
- upgrade-insecure-requests: Nalaže korisničkom agentu da automatski nadogradi nesigurne zahtjeve (HTTP) na sigurne zahtjeve (HTTPS).
- report-uri: Određuje URL na koji preglednik treba slati izvješća o kršenjima CSP-a. Ova je direktiva zastarjela i zamijenjena je s `report-to`.
- report-to: Određuje naziv grupe za izvješćivanje definiran u `Report-To` zaglavlju, na koju preglednik treba slati izvješća o kršenjima CSP-a.
Ključne riječi za listu izvora u CSP-u
Unutar CSP direktiva možete koristiti ključne riječi za listu izvora kako biste definirali dopuštene izvore. Evo nekih uobičajenih ključnih riječi:
- 'self': Dopušta resurse s istog izvora (shema i host) kao i dokument.
- 'none': Zabranjuje resurse sa svih izvora.
- 'unsafe-inline': Dopušta korištenje inline skripti i stilova (npr. <script> oznake i style atributi). Koristiti s iznimnim oprezom jer značajno slabi CSP zaštitu od XSS-a.
- 'unsafe-eval': Dopušta korištenje funkcija za dinamičko izvršavanje koda poput
eval()iFunction(). Koristiti s iznimnim oprezom jer uvodi značajne sigurnosne rizike. - 'unsafe-hashes': Dopušta određene inline rukovatelje događajima (event handlers) ili <style> oznake koji odgovaraju navedenom hashu. Zahtijeva podršku preglednika. Koristiti s oprezom.
- 'strict-dynamic': Određuje da se povjerenje izričito dano skripti prisutnoj u kodu, popraćeno nonceom ili hashem, prenosi na sve skripte koje ta korijenska skripta učitava.
- data: Dopušta data: URI-je (npr. inline slike kodirane kao base64). Koristiti s oprezom.
- https:: Dopušta učitavanje resursa putem HTTPS-a s bilo koje domene.
- [hostname]: Dopušta resurse s određene domene (npr. example.com). Možete navesti i broj porta (npr. example.com:8080).
- [scheme]://[hostname]:[port]: Potpuno kvalificirani URI, koji dopušta resurse s navedene sheme, hosta i porta.
Praktični primjeri CSP-a
Pogledajmo neke praktične primjere CSP zaglavlja:
Primjer 1: Osnovni CSP s 'self'
Ova politika dopušta resurse samo s istog izvora:
Content-Security-Policy: default-src 'self'
Primjer 2: Dopuštanje skripti s određene domene
Ova politika dopušta skripte s vaše vlastite domene i pouzdanog CDN-a:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Primjer 3: Onemogućavanje inline skripti i stilova
Ova politika zabranjuje inline skripte i stilove, što je snažna obrana od XSS-a:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Važno: Onemogućavanje inline skripti zahtijeva refaktoriranje vašeg HTML-a kako biste premjestili inline skripte u vanjske datoteke.
Primjer 4: Korištenje nonceova za inline skripte
Ako morate koristiti inline skripte, koristite nonceove (kriptografski nasumične, jednokratne tokene) kako biste na bijelu listu stavili određene blokove inline skripti. To je sigurnije od 'unsafe-inline'. Poslužitelj mora generirati jedinstveni nonce za svaki zahtjev i uključiti ga i u CSP zaglavlje i u <script> oznaku.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Napomena: Ne zaboravite generirati novi nonce za svaki zahtjev. Nemojte ponovno koristiti nonceove!
Primjer 5: Korištenje hasheva za inline stilove
Slično nonceovima, hashevi se mogu koristiti za stavljanje na bijelu listu određenih inline <style> blokova. To se radi generiranjem SHA256, SHA384 ili SHA512 hasha sadržaja stila.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Napomena: Hashevi su manje fleksibilni od nonceova jer će svaka promjena sadržaja stila poništiti hash.
Primjer 6: Prijavljivanje kršenja CSP-a
Za praćenje kršenja CSP-a, koristite direktivu report-uri ili report-to:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Također ćete morati konfigurirati Report-To zaglavlje. Report-To zaglavlje definira jednu ili više grupa za izvješćivanje, koje određuju gdje i kako se izvješća trebaju slati.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Testiranje i implementacija CSP-a
Implementacija CSP-a zahtijeva pažljivo planiranje i testiranje. Započnite s restriktivnom politikom i postupno je ublažavajte prema potrebi. Koristite zaglavlje Content-Security-Policy-Report-Only kako biste testirali svoju politiku bez blokiranja resursa. Ovo zaglavlje prijavljuje kršenja bez provođenja politike, omogućujući vam da identificirate i riješite probleme prije implementacije politike u produkciji.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analizirajte izvješća koja generira preglednik kako biste identificirali eventualna kršenja i prilagodili svoju politiku u skladu s tim. Kada ste sigurni da vaša politika ispravno radi, implementirajte je pomoću zaglavlja Content-Security-Policy.
Najbolje prakse za CSP
- Započnite s default-src: Uvijek definirajte
default-srckako biste uspostavili osnovnu politiku. - Budite specifični: Koristite specifične direktive i ključne riječi za listu izvora kako biste ograničili opseg svoje politike.
- Izbjegavajte 'unsafe-inline' i 'unsafe-eval': Ove ključne riječi značajno slabe CSP i treba ih izbjegavati kad god je to moguće.
- Koristite nonceove ili hasheve za inline skripte i stilove: Ako morate koristiti inline skripte ili stilove, koristite nonceove ili hasheve za stavljanje određenih blokova koda na bijelu listu.
- Pratite kršenja CSP-a: Koristite direktivu
report-uriilireport-toza praćenje kršenja CSP-a i prilagodite svoju politiku u skladu s tim. - Temeljito testirajte: Koristite zaglavlje
Content-Security-Policy-Report-Onlyza testiranje svoje politike prije implementacije u produkciji. - Iterirajte i poboljšavajte: CSP nije jednokratna konfiguracija. Kontinuirano pratite i poboljšavajte svoju politiku kako biste se prilagodili promjenama u svojoj aplikaciji i sigurnosnim prijetnjama.
Što je Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) je mehanizam koji omogućuje web stranicama s jednog izvora (domene) pristup resursima s drugog izvora. Prema zadanim postavkama, preglednici primjenjuju Politiku istog izvora (Same-Origin Policy), koja sprječava skripte da upućuju zahtjeve na izvor različit od onog s kojeg je skripta potekla. CORS pruža način za selektivno ublažavanje ovog ograničenja, dopuštajući legitimne međuizvorne (cross-origin) zahtjeve uz zaštitu od zlonamjernih napada.
Razumijevanje Politike istog izvora
Politika istog izvora temeljni je sigurnosni mehanizam koji sprječava zlonamjernu skriptu s jedne web stranice da pristupi osjetljivim podacima na drugoj. Izvor je definiran shemom (protokolom), hostom (domenom) i portom. Dva URL-a imaju isti izvor ako i samo ako imaju istu shemu, host i port.
Na primjer:
https://www.example.com/app1/index.htmlihttps://www.example.com/app2/index.htmlimaju isti izvor.https://www.example.com/index.htmlihttp://www.example.com/index.htmlimaju različite izvore (različita shema).https://www.example.com/index.htmlihttps://sub.example.com/index.htmlimaju različite izvore (različit host).https://www.example.com:8080/index.htmlihttps://www.example.com:80/index.htmlimaju različite izvore (različit port).
Kako CORS radi
Kada web stranica uputi međuizvorni zahtjev, preglednik prvo šalje "preflight" zahtjev poslužitelju. Preflight zahtjev koristi HTTP metodu OPTIONS i uključuje zaglavlja koja naznačuju HTTP metodu i zaglavlja koja će stvarni zahtjev koristiti. Poslužitelj zatim odgovara zaglavljima koja pokazuju je li međuizvorni zahtjev dopušten.
Ako poslužitelj dopusti zahtjev, u odgovor uključuje zaglavlje Access-Control-Allow-Origin. Ovo zaglavlje specificira izvore kojima je dopušten pristup resursu. Preglednik zatim nastavlja sa stvarnim zahtjevom. Ako poslužitelj ne dopusti zahtjev, ne uključuje zaglavlje Access-Control-Allow-Origin, a preglednik blokira zahtjev.
CORS zaglavlja: Detaljan pregled
CORS se oslanja na HTTP zaglavlja za komunikaciju između preglednika i poslužitelja. Evo ključnih CORS zaglavlja:
- Access-Control-Allow-Origin: Određuje izvore kojima je dopušten pristup resursu. Ovo zaglavlje može sadržavati određeni izvor (npr.
https://www.example.com), zamjenski znak (*) ilinull. Korištenje*dopušta zahtjeve s bilo kojeg izvora, što se općenito ne preporučuje iz sigurnosnih razloga. Korištenje `null` prikladno je samo za "neprozirne odgovore" (opaque responses), kao npr. kada se resurs dohvaća pomoću `file://` protokola ili data URI-ja. - Access-Control-Allow-Methods: Određuje HTTP metode koje su dopuštene za međuizvorni zahtjev (npr.
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Određuje HTTP zaglavlja koja su dopuštena u međuizvornom zahtjevu. Ovo je važno za rukovanje prilagođenim zaglavljima.
- Access-Control-Allow-Credentials: Označava treba li preglednik uključiti vjerodajnice (npr. kolačiće, autorizacijska zaglavlja) u međuizvorni zahtjev. Ovo zaglavlje mora biti postavljeno na
truekako bi se dopustile vjerodajnice. - Access-Control-Expose-Headers: Određuje koja zaglavlja mogu biti izložena klijentu. Prema zadanim postavkama, izložen je samo ograničen skup zaglavlja.
- Access-Control-Max-Age: Određuje maksimalno vrijeme (u sekundama) tijekom kojeg preglednik može predmemorirati preflight zahtjev.
- Origin: Ovo je zaglavlje zahtjeva koje šalje preglednik kako bi naznačio izvor zahtjeva.
- Vary: Opće HTTP zaglavlje, ali važno za CORS. Kada se `Access-Control-Allow-Origin` dinamički generira, zaglavlje `Vary: Origin` treba biti uključeno u odgovor kako bi se mehanizmima za predmemoriranje naložilo da odgovor varira ovisno o `Origin` zaglavlju zahtjeva.
Praktični primjeri CORS-a
Pogledajmo neke praktične primjere CORS konfiguracija:
Primjer 1: Dopuštanje zahtjeva s određenog izvora
Ova konfiguracija dopušta zahtjeve samo s https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
Primjer 2: Dopuštanje zahtjeva s bilo kojeg izvora (ne preporučuje se)
Ova konfiguracija dopušta zahtjeve s bilo kojeg izvora. Koristiti s oprezom jer može uvesti sigurnosne rizike:
Access-Control-Allow-Origin: *
Primjer 3: Dopuštanje određenih metoda i zaglavlja
Ova konfiguracija dopušta GET, POST i PUT metode te Content-Type i Authorization zaglavlja:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Primjer 4: Dopuštanje vjerodajnica
Da biste dopustili vjerodajnice (npr. kolačiće), morate postaviti Access-Control-Allow-Credentials na true i navesti određeni izvor (ne možete koristiti * kada dopuštate vjerodajnice):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Također trebate postaviti credentials: 'include' u svom JavaScript fetch/XMLHttpRequest zahtjevu.
fetch('https://api.example.com/data', {
credentials: 'include'
})
CORS preflight zahtjevi
Za određene vrste međuizvornih zahtjeva (npr. zahtjevi s prilagođenim zaglavljima ili metodama koje nisu GET, HEAD ili POST s Content-Type tipom application/x-www-form-urlencoded, multipart/form-data ili text/plain), preglednik šalje preflight zahtjev koristeći metodu OPTIONS. Poslužitelj mora odgovoriti na preflight zahtjev s odgovarajućim CORS zaglavljima kako bi naznačio je li stvarni zahtjev dopušten.
Evo primjera preflight zahtjeva i odgovora:
Preflight zahtjev (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Preflight odgovor (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Zaglavlje Access-Control-Max-Age određuje koliko dugo preglednik može predmemorirati preflight odgovor, smanjujući broj preflight zahtjeva.
CORS i JSONP
JSON with Padding (JSONP) je starija tehnika za zaobilaženje Politike istog izvora. Međutim, JSONP ima značajne sigurnosne rizike i treba ga izbjegavati u korist CORS-a. JSONP se oslanja na ubacivanje <script> oznaka u stranicu, što može izvršiti proizvoljan kod. CORS pruža sigurniji i fleksibilniji način za rukovanje međuizvornim zahtjevima.
Najbolje prakse za CORS
- Izbjegavajte korištenje *: Izbjegavajte korištenje zamjenskog znaka (*) u zaglavlju
Access-Control-Allow-Origin, jer dopušta zahtjeve s bilo kojeg izvora. Umjesto toga, navedite određene izvore kojima je dopušten pristup resursu. - Budite specifični s metodama i zaglavljima: Navedite točne HTTP metode i zaglavlja koja su dopuštena u zaglavljima
Access-Control-Allow-MethodsiAccess-Control-Allow-Headers. - Koristite Access-Control-Allow-Credentials s oprezom: Omogućite
Access-Control-Allow-Credentialssamo ako trebate dopustiti vjerodajnice (npr. kolačiće) u međuizvornim zahtjevima. Budite svjesni sigurnosnih implikacija dopuštanja vjerodajnica. - Osigurajte svoje preflight zahtjeve: Osigurajte da vaš poslužitelj ispravno rukuje preflight zahtjevima i vraća ispravna CORS zaglavlja.
- Koristite HTTPS: Uvijek koristite HTTPS i za izvor i za resurse kojima pristupate s drugog izvora. To pomaže u zaštiti od napada "čovjek u sredini" (man-in-the-middle).
- Vary: Origin: Ako dinamički generirate zaglavlje `Access-Control-Allow-Origin`, uvijek uključite zaglavlje `Vary: Origin` kako biste spriječili probleme s predmemoriranjem.
CSP i CORS u praksi: Kombinirani pristup
Iako se i CSP i CORS bave sigurnosnim problemima, djeluju na različitim slojevima i pružaju komplementarnu zaštitu. CSP se usredotočuje na sprječavanje preglednika da učitava zlonamjerni sadržaj, dok se CORS usredotočuje na kontrolu toga koji izvori mogu pristupiti resursima na vašem poslužitelju.
Kombiniranjem CSP-a i CORS-a možete stvoriti robusniju sigurnosnu poziciju za svoje web aplikacije. Na primjer, možete koristiti CSP za ograničavanje izvora s kojih se skripte mogu učitavati, a CORS za kontrolu toga koji izvori mogu pristupiti vašim API krajnjim točkama.
Primjer: Osiguravanje API-ja pomoću CSP-a i CORS-a
Recimo da imate API na https://api.example.com kojem želite omogućiti pristup samo s https://www.example.com. Možete konfigurirati svoj poslužitelj da vraća sljedeća zaglavlja:
Zaglavlja odgovora API-ja (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
A svoju web stranicu (https://www.example.com) možete konfigurirati da koristi sljedeće CSP zaglavlje:
CSP zaglavlje web stranice (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Ova CSP politika dopušta web stranici da učitava skripte i povezuje se s API-jem, ali sprječava učitavanje skripti ili povezivanje s drugim domenama.
Zaključak
Politika sigurnosti sadržaja (CSP) i Cross-Origin Resource Sharing (CORS) ključni su alati za jačanje sigurnosti vaših frontend aplikacija. Pažljivim konfiguriranjem CSP-a i CORS-a možete značajno smanjiti rizik od XSS napada, napada ubacivanjem podataka i drugih sigurnosnih ranjivosti. Ne zaboravite započeti s restriktivnom politikom, temeljito testirati te kontinuirano pratiti i poboljšavati svoju konfiguraciju kako biste se prilagodili promjenama u aplikaciji i rastućim sigurnosnim prijetnjama. Davanjem prioriteta sigurnosti frontenda, možete zaštititi svoje korisnike i osigurati integritet svojih web aplikacija u današnjem sve složenijem digitalnom svijetu.