Celovit vodnik za razumevanje in implementacijo deljenja virov med izvori (CORS) za varno komunikacijo v JavaScriptu med različnimi domenami.
Implementacija varnosti med izvori: najboljše prakse za komunikacijo v JavaScriptu
V današnjem medsebojno povezanem spletu morajo JavaScript aplikacije pogosto komunicirati z viri iz različnih izvorov (domen, protokolov ali vrat). To interakcijo ureja politika istega izvora v brskalniku, ključen varnostni mehanizem, zasnovan za preprečevanje zlonamernim skriptam dostopa do občutljivih podatkov preko meja domen. Vendar pa je legitimna komunikacija med različnimi izvori pogosto nujna. Tu nastopi deljenje virov med izvori (Cross-Origin Resource Sharing - CORS). Ta članek ponuja celovit pregled CORS-a, njegove implementacije in najboljših praks za varno komunikacijo med izvori v JavaScriptu.
Razumevanje politike istega izvora
Politika istega izvora (Same-Origin Policy - SOP) je temeljni varnostni koncept v spletnih brskalnikih. Omejuje skripte, ki se izvajajo na enem izvoru, pri dostopu do virov z drugega izvora. Izvor je definiran s kombinacijo protokola (npr. HTTP ali HTTPS), imena domene (npr. example.com) in številke vrat (npr. 80 ali 443). Dva URL-ja imata isti izvor le, če se vse tri komponente natančno ujemajo.
Na primer:
http://www.example.cominhttp://www.example.com/path: Isti izvorhttp://www.example.cominhttps://www.example.com: Drugačen izvor (drugačen protokol)http://www.example.cominhttp://subdomain.example.com: Drugačen izvor (drugačna domena)http://www.example.com:80inhttp://www.example.com:8080: Drugačen izvor (drugačna vrata)
SOP je ključna obramba pred napadi Cross-Site Scripting (XSS), kjer lahko zlonamerne skripte, vbrizgane na spletno stran, kradejo uporabniške podatke ali izvajajo nepooblaščena dejanja v imenu uporabnika.
Kaj je deljenje virov med izvori (CORS)?
CORS je mehanizem, ki uporablja HTTP glave, da strežnikom omogoči, da določijo, kateri izvori (domene, sheme ali vrata) imajo dovoljenje za dostop do njihovih virov. V bistvu sprošča politiko istega izvora za določene zahteve med izvori, kar omogoča legitimno komunikacijo, hkrati pa še vedno ščiti pred zlonamernimi napadi.
CORS deluje tako, da doda nove HTTP glave, ki določajo dovoljene izvore in metode (npr. GET, POST, PUT, DELETE), ki so dovoljene za zahteve med izvori. Ko brskalnik izvede zahtevo med izvori, pošlje glavo Origin z zahtevo. Strežnik odgovori z glavo Access-Control-Allow-Origin, ki določa dovoljen(e) izvor(e). Če se izvor zahteve ujema z vrednostjo v glavi Access-Control-Allow-Origin (ali če je vrednost *), brskalnik dovoli JavaScript kodi dostop do odgovora.
Kako deluje CORS: podrobna razlaga
Proces CORS običajno vključuje dve vrsti zahtev:
- Enostavne zahteve: To so zahteve, ki izpolnjujejo določene kriterije. Če zahteva izpolnjuje te pogoje, brskalnik neposredno pošlje zahtevo.
- Predhodne zahteve (Preflighted Requests): To so bolj zapletene zahteve, ki od brskalnika zahtevajo, da najprej pošlje "predhodno" zahtevo OPTIONS na strežnik, da ugotovi, ali je dejansko zahtevo varno poslati.
1. Enostavne zahteve
Zahteva se šteje za "enostavno", če izpolnjuje vse naslednje pogoje:
- Metoda je
GET,HEADaliPOST. - Če je metoda
POST, je glavaContent-Typeena od naslednjih: application/x-www-form-urlencodedmultipart/form-datatext/plain- Niso nastavljene nobene glave po meri.
Primer enostavne zahteve:
GET /resource HTTP/1.1
Origin: http://www.example.com
Primer odgovora strežnika, ki dovoljuje izvor:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Content-Type: application/json
{
"data": "Some data"
}
Če je glava Access-Control-Allow-Origin prisotna in se njena vrednost ujema z izvorom zahteve ali je nastavljena na *, brskalnik dovoli skripti dostop do podatkov v odgovoru. V nasprotnem primeru brskalnik blokira dostop do odgovora, v konzoli pa se prikaže sporočilo o napaki.
2. Predhodne zahteve (Preflighted Requests)
Zahteva se šteje za "predhodno", če ne izpolnjuje kriterijev za enostavno zahtevo. To se običajno zgodi, ko zahteva uporablja drugačno HTTP metodo (npr. PUT, DELETE), nastavlja glave po meri ali uporablja Content-Type, ki ni med dovoljenimi vrednostmi.
Pred pošiljanjem dejanske zahteve brskalnik najprej pošlje zahtevo OPTIONS na strežnik. Ta "predhodna" zahteva vključuje naslednje glave:
Origin: Izvor strani, ki zahteva.Access-Control-Request-Method: HTTP metoda, ki se bo uporabila v dejanski zahtevi (npr.PUT,DELETE).Access-Control-Request-Headers: Z vejico ločen seznam glav po meri, ki bodo poslane v dejanski zahtevi.
Primer predhodne zahteve:
OPTIONS /resource HTTP/1.1
Origin: http://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header, Content-Type
Strežnik mora na zahtevo OPTIONS odgovoriti z naslednjimi glavami:
Access-Control-Allow-Origin: Izvor, ki sme izvesti zahtevo (ali*za dovoljenje katerega koli izvora).Access-Control-Allow-Methods: Z vejico ločen seznam HTTP metod, ki so dovoljene za zahteve med izvori (npr.GET,POST,PUT,DELETE).Access-Control-Allow-Headers: Z vejico ločen seznam glav po meri, ki jih je dovoljeno poslati v zahtevi.Access-Control-Max-Age: Število sekund, za katere lahko brskalnik predpomni odgovor na predhodno zahtevo.
Primer odgovora strežnika na predhodno zahtevo:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header, Content-Type
Access-Control-Max-Age: 86400
Če odgovor strežnika na predhodno zahtevo pokaže, da je dejanska zahteva dovoljena, bo brskalnik nato poslal dejansko zahtevo. V nasprotnem primeru bo brskalnik blokiral zahtevo in prikazal sporočilo o napaki.
Implementacija CORS na strani strežnika
CORS se primarno implementira na strani strežnika z nastavitvijo ustreznih HTTP glav v odgovoru. Specifične podrobnosti implementacije se razlikujejo glede na uporabljeno strežniško tehnologijo.
Primer uporabe Node.js z Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Omogoči CORS za vse izvore
app.use(cors());
// Alternativno, konfigurirajte CORS za določene izvore
// const corsOptions = {
// origin: 'http://www.example.com'
// };
// app.use(cors(corsOptions));
app.get('/resource', (req, res) => {
res.json({ message: 'This is a CORS-enabled resource' });
});
app.listen(3000, () => {
console.log('Strežnik posluša na vratih 3000');
});
Vmesna programska oprema cors poenostavi postopek nastavljanja CORS glav v Expressu. CORS lahko omogočite za vse izvore z uporabo cors() ali ga konfigurirate za določene izvore z uporabo cors(corsOptions).
Primer uporabe Pythona s Flaskom:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/resource")
def hello():
return {"message": "This is a CORS-enabled resource"}
if __name__ == '__main__':
app.run(debug=True)
Razširitev flask_cors omogoča preprost način za omogočanje CORS-a v Flask aplikacijah. CORS lahko omogočite za vse izvore tako, da app predate CORS(). Možna je tudi konfiguracija za določene izvore.
Primer uporabe Jave s Spring Boot:
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("/resource")
.allowedOrigins("http://www.example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("Content-Type", "X-Custom-Header")
.allowCredentials(true)
.maxAge(3600);
}
}
V Spring Bootu lahko CORS konfigurirate z uporabo WebMvcConfigurer. To omogoča natančen nadzor nad dovoljenimi izvori, metodami, glavami in drugimi CORS nastavitvami.
Neposredno nastavljanje CORS glav (splošen primer)
Če ne uporabljate nobenega ogrodja, lahko glave nastavite neposredno v svoji strežniški kodi (npr. PHP, Ruby on Rails itd.):
Najboljše prakse za CORS
Za zagotovitev varne in učinkovite komunikacije med izvori upoštevajte te najboljše prakse:
- Izogibajte se uporabi
Access-Control-Allow-Origin: *v produkciji: Dovoljenje vsem izvorom za dostop do vaših virov je lahko varnostno tveganje. Namesto tega določite točne izvore, ki so dovoljeni. - Uporabljajte HTTPS: Vedno uporabljajte HTTPS za izvor, ki pošilja zahtevo, in za izvor, ki jo sprejema, da zaščitite podatke med prenosom.
- Preverjajte vnos: Vedno preverjajte in čistite podatke, prejete iz zahtev med izvori, da preprečite napade z vbrizgavanjem.
- Implementirajte ustrezno avtentikacijo in avtorizacijo: Zagotovite, da lahko do občutljivih virov dostopajo samo pooblaščeni uporabniki.
- Predpomnite odgovore na predhodne zahteve: Uporabite
Access-Control-Max-Ageza predpomnjenje odgovorov na predhodne zahteve in zmanjšanje števila zahtevOPTIONS. - Razmislite o uporabi poverilnic: Če vaš API zahteva avtentikacijo s piškotki ali HTTP avtentikacijo, morate na strežniku nastaviti glavo
Access-Control-Allow-Credentialsnatruein možnostcredentialsna'include'v vaši JavaScript kodi (npr. pri uporabifetchaliXMLHttpRequest). Bodite izjemno previdni pri uporabi te možnosti, saj lahko povzroči varnostne ranljivosti, če se z njo ne ravna pravilno. Poleg tega, ko je Access-Control-Allow-Credentials nastavljen na true, Access-Control-Allow-Origin ne more biti nastavljen na "*". Eksplicitno morate določiti dovoljen(e) izvor(e). - Redno pregledujte in posodabljajte konfiguracijo CORS: Ko se vaša aplikacija razvija, redno pregledujte in posodabljajte svojo konfiguracijo CORS, da zagotovite, da ostaja varna in ustreza vašim potrebam.
- Razumejte posledice različnih konfiguracij CORS: Zavedajte se varnostnih posledic različnih konfiguracij CORS in izberite konfiguracijo, ki je primerna za vašo aplikacijo.
- Testirajte svojo implementacijo CORS: Temeljito testirajte svojo implementacijo CORS, da zagotovite, da deluje, kot je pričakovano, in da ne uvaja nobenih varnostnih ranljivosti. Uporabite razvijalska orodja brskalnika za pregled omrežnih zahtev in odgovorov ter avtomatizirana orodja za testiranje, da preverite delovanje CORS.
Primer: Uporaba Fetch API s CORS
Tukaj je primer, kako uporabiti fetch API za izvedbo zahteve med izvori:
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors', // Sporoči brskalniku, da gre za CORS zahtevo
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
}
})
.then(response => {
if (!response.ok) {
throw new Error('Odziv omrežja ni bil v redu');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Prišlo je do težave pri operaciji fetch:', error);
});
Možnost mode: 'cors' sporoči brskalniku, da gre za CORS zahtevo. Če strežnik ne dovoli izvora, bo brskalnik blokiral dostop do odgovora in sprožena bo napaka.
Če uporabljate poverilnice (npr. piškotke), morate možnost credentials nastaviti na 'include':
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors',
credentials: 'include', // Vključi piškotke v zahtevo
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
// ...
});
CORS in JSONP
JSON s podlogo (JSON with Padding - JSONP) je starejša tehnika za obhod politike istega izvora. Deluje tako, da dinamično ustvari oznako <script>, ki nalaga podatke z druge domene. Čeprav je JSONP v določenih situacijah lahko uporaben, ima pomembne varnostne omejitve in se mu je treba, kadar je to mogoče, izogibati. CORS je prednostna rešitev za komunikacijo med izvori, saj zagotavlja varnejši in bolj prilagodljiv mehanizem.
Ključne razlike med CORS in JSONP:
- Varnost: CORS je varnejši od JSONP, ker strežniku omogoča nadzor nad tem, kateri izvori smejo dostopati do njegovih virov. JSONP ne zagotavlja nobenega nadzora nad izvorom.
- HTTP metode: CORS podpira vse HTTP metode (npr.
GET,POST,PUT,DELETE), medtem ko JSONP podpira samo zahteveGET. - Obravnavanje napak: CORS zagotavlja boljše obravnavanje napak kot JSONP. Ko zahteva CORS ne uspe, brskalnik prikaže podrobna sporočila o napakah. Obravnavanje napak pri JSONP je omejeno na zaznavanje, ali se je skripta uspešno naložila.
Odpravljanje težav s CORS
Težave s CORS so lahko frustrirajoče za odpravljanje. Tu je nekaj pogostih nasvetov za odpravljanje težav:
- Preverite konzolo brskalnika: Konzola brskalnika običajno prikaže podrobna sporočila o napakah v zvezi s CORS.
- Preglejte omrežne zahteve: Uporabite razvijalska orodja brskalnika za pregled HTTP glav tako zahteve kot odgovora. Preverite, ali sta glavi
OrigininAccess-Control-Allow-Originpravilno nastavljeni. - Preverite konfiguracijo na strani strežnika: Dvakrat preverite svojo strežniško konfiguracijo CORS, da zagotovite, da dovoljuje pravilne izvore, metode in glave.
- Počistite predpomnilnik brskalnika: Včasih lahko predpomnjeni odgovori na predhodne zahteve povzročijo težave s CORS. Poskusite počistiti predpomnilnik brskalnika ali uporabiti zasebno okno za brskanje.
- Uporabite CORS proxy: V nekaterih primerih boste morda morali uporabiti CORS proxy za obhod omejitev CORS. Vendar se zavedajte, da lahko uporaba CORS proxyja prinese varnostna tveganja.
- Preverite za napačne konfiguracije: Poiščite pogoste napačne konfiguracije, kot so manjkajoča glava
Access-Control-Allow-Origin, napačne vrednostiAccess-Control-Allow-MethodsaliAccess-Control-Allow-Headersali napačna glavaOriginv zahtevi.
Zaključek
Deljenje virov med izvori (CORS) je bistven mehanizem za omogočanje varne komunikacije med izvori v JavaScript aplikacijah. Z razumevanjem politike istega izvora, poteka dela CORS in različnih vpletenih HTTP glav lahko razvijalci učinkovito implementirajo CORS za zaščito svojih aplikacij pred varnostnimi ranljivostmi, hkrati pa dovolijo legitimne zahteve med izvori. Upoštevanje najboljših praks za konfiguracijo CORS in redno pregledovanje vaše implementacije sta ključna za ohranjanje varne in robustne spletne aplikacije.
Ta celovit vodnik ponuja trdne temelje za razumevanje in implementacijo CORS. Ne pozabite se posvetovati z uradno dokumentacijo in viri za vašo specifično strežniško tehnologijo, da zagotovite, da CORS implementirate pravilno in varno.