Celovit vodnik za izboljšanje varnosti frontend aplikacij z uporabo CSP in CORS, ki ščiti vaše spletne aplikacije pred sodobnimi grožnjami.
Krepitev varnosti uporabniškega vmesnika: Varnostna politika vsebine (CSP) in CORS
V današnjem medsebojno povezanem digitalnem svetu je varnost uporabniškega vmesnika (frontend) ključnega pomena. Spletne aplikacije so vse pogosteje tarča sofisticiranih napadov, zato so robustni varnostni ukrepi nujni. Dve ključni komponenti varne frontend arhitekture sta Varnostna politika vsebine (Content Security Policy - CSP) in Mehanizem za souporabo virov z različnih izvorov (Cross-Origin Resource Sharing - CORS). Ta celovit vodnik ponuja poglobljen vpogled v ti tehnologiji, z praktičnimi primeri in uporabnimi nasveti, ki vam bodo pomagali okrepiti vaše spletne aplikacije pred sodobnimi grožnjami.
Kaj je Varnostna politika vsebine (CSP)?
Varnostna politika vsebine (CSP) je dodaten varnostni sloj, ki pomaga pri odkrivanju in blaženju določenih vrst napadov, vključno z napadi skriptiranja med spletnimi mesti (Cross-Site Scripting - XSS) in napadi z vbrizgavanjem podatkov. CSP se implementira tako, da spletni strežnik brskalniku pošlje HTTP odzivno glavo Content-Security-Policy. Ta glava določa seznam dovoljenih virov (whitelist), iz katerih lahko brskalnik nalaga vire. Z omejevanjem virov vsebine, ki jih brskalnik lahko naloži, CSP napadalcem bistveno oteži vbrizgavanje zlonamerne kode na vašo spletno stran.
Kako deluje CSP
CSP deluje tako, da brskalniku naroči nalaganje virov (npr. skript, slogovnih datotek, slik, pisav) samo iz odobrenih virov. Ti viri so določeni v glavi CSP z uporabo direktiv. Če brskalnik poskuša naložiti vir iz vira, ki ni izrecno dovoljen, bo zahtevo blokiral in poročal o kršitvi.
Direktive CSP: Celovit pregled
Direktive CSP nadzorujejo vrste virov, ki jih je mogoče naložiti iz določenih virov. Sledi razčlenitev nekaterih najpomembnejših direktiv:
- default-src: Določa privzeti vir za vse vrste vsebin. To je nadomestna direktiva, ki se uporabi, kadar druge, bolj specifične direktive niso prisotne.
- script-src: Določa vire, iz katerih se lahko nalagajo skripte. To je ključnega pomena za preprečevanje napadov XSS.
- style-src: Določa vire, iz katerih se lahko nalagajo slogovne datoteke.
- img-src: Določa vire, iz katerih se lahko nalagajo slike.
- font-src: Določa vire, iz katerih se lahko nalagajo pisave.
- media-src: Določa vire, iz katerih se lahko nalagata zvok in video.
- object-src: Določa vire, iz katerih se lahko nalagajo vtičniki (npr. Flash). Pogosto je nastavljena na 'none', da se vtičniki popolnoma onemogočijo zaradi njihovih inherentnih varnostnih tveganj.
- frame-src: Določa vire, iz katerih se lahko nalagajo okvirji (npr. <iframe>).
- connect-src: Določa URL-je, s katerimi se lahko uporabniški agent povezuje prek skriptnih vmesnikov, kot so XMLHttpRequest, WebSocket in EventSource.
- base-uri: Določa URL-je, ki se lahko uporabljajo v elementu <base> dokumenta.
- form-action: Določa URL-je, na katere se lahko pošiljajo oddaje obrazcev.
- upgrade-insecure-requests: Naroči uporabniškemu agentu, naj samodejno nadgradi nevarne zahteve (HTTP) v varne zahteve (HTTPS).
- report-uri: Določa URL, kamor naj brskalnik pošilja poročila o kršitvah CSP. Ta direktiva je zastarela v korist `report-to`.
- report-to: Določa ime skupine za poročanje, definirano v glavi `Report-To`, kamor naj brskalnik pošilja poročila o kršitvah CSP.
Ključne besede seznama virov CSP
Znotraj direktiv CSP lahko za določanje dovoljenih virov uporabite ključne besede seznama virov. Tukaj je nekaj pogostih ključnih besed:
- 'self': Dovoljuje vire iz istega izvora (shema in gostitelj) kot dokument.
- 'none': Prepoveduje vire iz vseh virov.
- 'unsafe-inline': Dovoljuje uporabo vgrajenih skript in slogov (npr. <script> oznake in style atributi). Uporabljajte z izjemno previdnostjo, saj bistveno oslabi zaščito CSP pred XSS.
- 'unsafe-eval': Dovoljuje uporabo funkcij za dinamično vrednotenje kode, kot sta
eval()inFunction(). Uporabljajte z izjemno previdnostjo, saj prinaša znatna varnostna tveganja. - 'unsafe-hashes': Dovoljuje določene vgrajene obravnavalnike dogodkov ali oznake <style>, ki se ujemajo z določenim zgoščenim ključem (hash). Zahteva podporo brskalnika. Uporabljajte previdno.
- 'strict-dynamic': Določa, da se zaupanje, ki je izrecno dano skriptu v oznaki z dodanim "nonce" ali zgoščenim ključem, prenese na vse skripte, ki jih naloži ta korenski skript.
- data: Dovoljuje URI-je data: (npr. vgrajene slike, kodirane kot base64). Uporabljajte previdno.
- https:: Dovoljuje nalaganje virov prek HTTPS iz katere koli domene.
- [hostname]: Dovoljuje vire iz določene domene (npr. example.com). Določite lahko tudi številko vrat (npr. example.com:8080).
- [scheme]://[hostname]:[port]: Popolnoma kvalificiran URI, ki dovoljuje vire iz določene sheme, gostitelja in vrat.
Praktični primeri CSP
Oglejmo si nekaj praktičnih primerov glav CSP:
Primer 1: Osnovni CSP z 'self'
Ta politika dovoljuje vire samo iz istega izvora:
Content-Security-Policy: default-src 'self'
Primer 2: Dovoljevanje skript iz določene domene
Ta politika dovoljuje skripte iz vaše lastne domene in zaupanja vrednega CDN-ja:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Primer 3: Onemogočanje vgrajenih skript in slogov
Ta politika prepoveduje vgrajene skripte in sloge, kar je močna obramba pred XSS:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Pomembno: Onemogočanje vgrajenih skript zahteva preoblikovanje vaše HTML kode, da se vgrajene skripte premaknejo v zunanje datoteke.
Primer 4: Uporaba "nonce" za vgrajene skripte
Če morate uporabljati vgrajene skripte, uporabite "nonce" (kriptografsko naključne, enkratne žetone) za dodajanje določenih blokov vgrajenih skript na seznam dovoljenih. To je varneje kot 'unsafe-inline'. Strežnik mora za vsako zahtevo ustvariti edinstven "nonce" in ga vključiti tako v glavo CSP kot v oznako <script>.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Opomba: Ne pozabite ustvariti novega "nonce" za vsako zahtevo. Ne uporabljajte istih "nonce" večkrat!
Primer 5: Uporaba zgoščenih ključev (hashes) za vgrajene sloge
Podobno kot "nonce", se lahko za dodajanje določenih vgrajenih blokov <style> na seznam dovoljenih uporabijo zgoščeni ključi (hashes). To se naredi z generiranjem zgoščenega ključa SHA256, SHA384 ali SHA512 vsebine sloga.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Opomba: Zgoščeni ključi so manj prilagodljivi kot "nonce", saj bo vsaka sprememba vsebine sloga razveljavila zgoščeni ključ.
Primer 6: Poročanje o kršitvah CSP
Za spremljanje kršitev CSP uporabite direktivo report-uri ali report-to:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Prav tako boste morali konfigurirati glavo Report-To. Glava Report-To določa eno ali več skupin za poročanje, ki določajo, kam in kako naj se poročila pošiljajo.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Testiranje in uvajanje CSP
Implementacija CSP zahteva skrbno načrtovanje in testiranje. Začnite z omejevalno politiko in jo postopoma sproščajte po potrebi. Uporabite glavo Content-Security-Policy-Report-Only za testiranje vaše politike brez blokiranja virov. Ta glava poroča o kršitvah, ne da bi uveljavljala politiko, kar vam omogoča, da prepoznate in odpravite težave, preden politiko uvedete v produkcijo.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analizirajte poročila, ki jih ustvari brskalnik, da prepoznate morebitne kršitve in ustrezno prilagodite svojo politiko. Ko ste prepričani, da vaša politika deluje pravilno, jo uvedite z glavo Content-Security-Policy.
Najboljše prakse za CSP
- Začnite z default-src: Vedno določite
default-src, da vzpostavite osnovno politiko. - Bodite specifični: Uporabite specifične direktive in ključne besede seznama virov, da omejite obseg vaše politike.
- Izogibajte se 'unsafe-inline' in 'unsafe-eval': Te ključne besede bistveno oslabijo CSP in se jim je treba izogibati, kadar koli je to mogoče.
- Uporabite "nonce" ali zgoščene ključe za vgrajene skripte in sloge: Če morate uporabljati vgrajene skripte ali sloge, uporabite "nonce" ali zgoščene ključe za dodajanje določenih blokov kode na seznam dovoljenih.
- Spremljajte kršitve CSP: Uporabite direktivo
report-urialireport-toza spremljanje kršitev CSP in ustrezno prilagajanje vaše politike. - Temeljito testirajte: Uporabite glavo
Content-Security-Policy-Report-Onlyza testiranje vaše politike, preden jo uvedete v produkcijo. - Ponavljajte in izboljšujte: CSP ni enkratna nastavitev. Nenehno spremljajte in izboljšujte svojo politiko, da se prilagodite spremembam v vaši aplikaciji in grožnjam v okolju.
Kaj je mehanizem za souporabo virov z različnih izvorov (CORS)?
Mehanizem za souporabo virov z različnih izvorov (CORS) je mehanizem, ki spletnim stranem iz enega izvora (domene) omogoča dostop do virov iz drugega izvora. Brskalniki privzeto uveljavljajo politiko istega izvora (Same-Origin Policy), ki skriptam preprečuje pošiljanje zahtev na drug izvor, kot je tisti, iz katerega izvira skript. CORS ponuja način za selektivno sproščanje te omejitve, kar omogoča legitimne zahteve z različnih izvorov, hkrati pa ščiti pred zlonamernimi napadi.
Razumevanje politike istega izvora
Politika istega izvora je temeljni varnostni mehanizem, ki preprečuje, da bi zlonamerni skript z ene spletne strani dostopal do občutljivih podatkov na drugi spletni strani. Izvor je določen s shemo (protokolom), gostiteljem (domeno) in vrati. Dva URL-ja imata isti izvor, če in samo če imata enako shemo, gostitelja in vrata.
Na primer:
https://www.example.com/app1/index.htmlinhttps://www.example.com/app2/index.htmlimata isti izvor.https://www.example.com/index.htmlinhttp://www.example.com/index.htmlimata različen izvor (različna shema).https://www.example.com/index.htmlinhttps://sub.example.com/index.htmlimata različen izvor (različen gostitelj).https://www.example.com:8080/index.htmlinhttps://www.example.com:80/index.htmlimata različen izvor (različna vrata).
Kako deluje CORS
Ko spletna stran pošlje zahtevo z različnih izvorov, brskalnik najprej pošlje strežniku "preflight" zahtevo. "Preflight" zahteva uporablja metodo HTTP OPTIONS in vključuje glave, ki označujejo metodo HTTP in glave, ki jih bo uporabila dejanska zahteva. Strežnik se nato odzove z glavami, ki označujejo, ali je zahteva z različnih izvorov dovoljena.
Če strežnik dovoli zahtevo, v odgovor vključi glavo Access-Control-Allow-Origin. Ta glava določa izvor(e), ki imajo dovoljen dostop do vira. Brskalnik nato nadaljuje z dejansko zahtevo. Če strežnik ne dovoli zahteve, ne vključi glave Access-Control-Allow-Origin in brskalnik zahtevo blokira.
Glave CORS: Podroben pregled
CORS se za komunikacijo med brskalnikom in strežnikom zanaša na glave HTTP. Tukaj so ključne glave CORS:
- Access-Control-Allow-Origin: Določa izvor(e), ki imajo dovoljen dostop do vira. Ta glava lahko vsebuje določen izvor (npr.
https://www.example.com), nadomestni znak (*) alinull. Uporaba*dovoljuje zahteve iz katerega koli izvora, kar iz varnostnih razlogov na splošno ni priporočljivo. Uporaba `null` je primerna samo za "nepregledne odzive", na primer, ko je vir pridobljen s protokolom `file://` ali URI-jem podatkov. - Access-Control-Allow-Methods: Določa metode HTTP, ki so dovoljene za zahtevo z različnih izvorov (npr.
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Določa glave HTTP, ki so dovoljene v zahtevi z različnih izvorov. To je pomembno za obravnavo glav po meri.
- Access-Control-Allow-Credentials: Označuje, ali naj brskalnik v zahtevo z različnih izvorov vključi poverilnice (npr. piškotke, avtorizacijske glave). Ta glava mora biti nastavljena na
true, da se dovolijo poverilnice. - Access-Control-Expose-Headers: Določa, katere glave so lahko izpostavljene odjemalcu. Privzeto je izpostavljen le omejen nabor glav.
- Access-Control-Max-Age: Določa najdaljši čas (v sekundah), za katerega lahko brskalnik predpomni "preflight" zahtevo.
- Origin: To je glava zahteve, ki jo pošlje brskalnik, da označi izvor zahteve.
- Vary: Splošna glava HTTP, vendar pomembna za CORS. Kadar se glava `Access-Control-Allow-Origin` generira dinamično, je treba v odgovor vključiti glavo `Vary: Origin`, da se mehanizmom za predpomnjenje sporoči, da se odgovor razlikuje glede na glavo zahteve `Origin`.
Praktični primeri CORS
Oglejmo si nekaj praktičnih primerov konfiguracij CORS:
Primer 1: Dovoljevanje zahtev iz določenega izvora
Ta konfiguracija dovoljuje zahteve samo iz https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
Primer 2: Dovoljevanje zahtev iz katerega koli izvora (ni priporočljivo)
Ta konfiguracija dovoljuje zahteve iz katerega koli izvora. Uporabljajte previdno, saj lahko prinese varnostna tveganja:
Access-Control-Allow-Origin: *
Primer 3: Dovoljevanje določenih metod in glav
Ta konfiguracija dovoljuje metode GET, POST in PUT ter glavi Content-Type in Authorization:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Primer 4: Dovoljevanje poverilnic
Za dovoljenje poverilnic (npr. piškotkov) morate nastaviti Access-Control-Allow-Credentials na true in določiti specifičen izvor (ne morete uporabiti *, ko dovoljujete poverilnice):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Prav tako morate v svoji JavaScript zahtevi fetch/XMLHttpRequest nastaviti credentials: 'include'.
fetch('https://api.example.com/data', {
credentials: 'include'
})
"Preflight" zahteve CORS
Za določene vrste zahtev z različnih izvorov (npr. zahteve z glavami po meri ali metodami, ki niso GET, HEAD ali POST z Content-Type vrednostjo application/x-www-form-urlencoded, multipart/form-data ali text/plain), brskalnik pošlje "preflight" zahtevo z metodo OPTIONS. Strežnik se mora na "preflight" zahtevo odzvati z ustreznimi glavami CORS, da označi, ali je dejanska zahteva dovoljena.
Tukaj je primer "preflight" zahteve in odgovora:
"Preflight" zahteva (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
Glava Access-Control-Max-Age določa, kako dolgo lahko brskalnik predpomni "preflight" odgovor, kar zmanjša število "preflight" zahtev.
CORS in JSONP
JSON with Padding (JSONP) je starejša tehnika za obhod politike istega izvora. Vendar ima JSONP znatna varnostna tveganja in se mu je treba izogibati v korist CORS-a. JSONP se zanaša na vbrizgavanje oznak <script> v stran, kar lahko izvede poljubno kodo. CORS ponuja varnejši in bolj prilagodljiv način za obravnavo zahtev z različnih izvorov.
Najboljše prakse za CORS
- Izogibajte se uporabi *: Izogibajte se uporabi nadomestnega znaka (*) v glavi
Access-Control-Allow-Origin, saj dovoljuje zahteve iz katerega koli izvora. Namesto tega določite specifičen izvor(e), ki ima(jo) dovoljen dostop do vira. - Bodite specifični z metodami in glavami: Določite natančne metode HTTP in glave, ki so dovoljene v glavah
Access-Control-Allow-MethodsinAccess-Control-Allow-Headers. - Previdno uporabljajte Access-Control-Allow-Credentials: Omogočite
Access-Control-Allow-Credentialssamo, če morate dovoliti poverilnice (npr. piškotke) v zahtevah z različnih izvorov. Zavedajte se varnostnih posledic dovoljevanja poverilnic. - Zavarujte svoje "preflight" zahteve: Zagotovite, da vaš strežnik pravilno obravnava "preflight" zahteve in vrača pravilne glave CORS.
- Uporabljajte HTTPS: Vedno uporabljajte HTTPS tako za izvor kot za vire, do katerih dostopate z različnih izvorov. To pomaga pri zaščiti pred napadi "man-in-the-middle".
- Vary: Origin: Če dinamično generirate glavo `Access-Control-Allow-Origin`, vedno vključite glavo `Vary: Origin`, da preprečite težave s predpomnjenjem.
CSP in CORS v praksi: Kombiniran pristop
Čeprav tako CSP kot CORS obravnavata varnostne pomisleke, delujeta na različnih ravneh in zagotavljata dopolnilno zaščito. CSP se osredotoča na preprečevanje nalaganja zlonamerne vsebine v brskalniku, medtem ko se CORS osredotoča na nadzor, kateri izvori lahko dostopajo do virov na vašem strežniku.
Z združevanjem CSP in CORS lahko ustvarite bolj robustno varnostno držo za svoje spletne aplikacije. Na primer, lahko uporabite CSP za omejevanje virov, iz katerih se lahko nalagajo skripte, in CORS za nadzor, kateri izvori lahko dostopajo do vaših končnih točk API-ja.
Primer: Zavarovanje API-ja s CSP in CORS
Recimo, da imate API, ki gostuje na https://api.example.com in želite, da je dostopen samo iz https://www.example.com. Svoj strežnik lahko konfigurirate tako, da vrača naslednje glave:
Glave odgovora API-ja (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
In svojo spletno stran (https://www.example.com) lahko konfigurirate za uporabo naslednje glave CSP:
Glava CSP spletne strani (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Ta politika CSP spletni strani dovoljuje nalaganje skript in povezovanje z API-jem, vendar ji preprečuje nalaganje skript ali povezovanje z drugimi domenami.
Zaključek
Varnostna politika vsebine (CSP) in mehanizem za souporabo virov z različnih izvorov (CORS) sta bistvena orodja za krepitev varnosti vaših frontend aplikacij. S skrbno konfiguracijo CSP in CORS lahko znatno zmanjšate tveganje za napade XSS, napade z vbrizgavanjem podatkov in druge varnostne ranljivosti. Ne pozabite začeti z omejevalno politiko, temeljito testirati in nenehno spremljati ter izboljševati svojo konfiguracijo, da se prilagodite spremembam v vaši aplikaciji in razvijajočim se grožnjam v okolju. Z dajanjem prednosti varnosti uporabniškega vmesnika lahko zaščitite svoje uporabnike in zagotovite integriteto svojih spletnih aplikacij v današnjem vse bolj kompleksnem digitalnem svetu.