Išsamus vadovas, kaip suprasti ir įdiegti skirtingų kilmės šaltinių išteklių bendrinimą (CORS) saugiai JavaScript komunikacijai tarp skirtingų domenų.
Skirtingų kilmės šaltinių saugumo įgyvendinimas: JavaScript komunikacijos geriausios praktikos
Šiuolaikiniame susietame internete JavaScript programos dažnai turi sąveikauti su ištekliais iš skirtingų kilmės šaltinių (domenų, protokolų ar prievadų). Šią sąveiką reglamentuoja naršyklės tos pačios kilmės politika (Same-Origin Policy) – esminis saugumo mechanizmas, skirtas apsaugoti nuo kenkėjiškų scenarijų prieigos prie jautrių duomenų per domenų ribas. Tačiau teisėta komunikacija tarp skirtingų kilmės šaltinių dažnai yra būtina. Būtent čia į pagalbą ateina skirtingų kilmės šaltinių išteklių bendrinimas (Cross-Origin Resource Sharing, CORS). Šiame straipsnyje pateikiama išsami CORS apžvalga, jo įgyvendinimas ir geriausios praktikos saugiai komunikacijai tarp skirtingų kilmės šaltinių naudojant JavaScript.
Tos pačios kilmės politikos (Same-Origin Policy) supratimas
Tos pačios kilmės politika (SOP) yra pagrindinė saugumo koncepcija interneto naršyklėse. Ji apriboja scenarijus, veikiančius viename kilmės šaltinyje, nuo prieigos prie išteklių iš kito kilmės šaltinio. Kilmės šaltinis apibrėžiamas protokolo (pvz., HTTP arba HTTPS), domeno vardo (pvz., example.com) ir prievado numerio (pvz., 80 arba 443) deriniu. Du URL turi tą patį kilmės šaltinį tik tada, kai visi trys komponentai tiksliai sutampa.
Pavyzdžiui:
http://www.example.comirhttp://www.example.com/path: Tas pats kilmės šaltinishttp://www.example.comirhttps://www.example.com: Skirtingas kilmės šaltinis (skirtingas protokolas)http://www.example.comirhttp://subdomain.example.com: Skirtingas kilmės šaltinis (skirtingas domenas)http://www.example.com:80irhttp://www.example.com:8080: Skirtingas kilmės šaltinis (skirtingas prievadas)
SOP yra kritinė apsauga nuo „Cross-Site Scripting“ (XSS) atakų, kai į svetainę įterpti kenkėjiški scenarijai gali pavogti vartotojo duomenis arba atlikti neteisėtus veiksmus vartotojo vardu.
Kas yra skirtingų kilmės šaltinių išteklių bendrinimas (CORS)?
CORS yra mechanizmas, kuris naudoja HTTP antraštes, leidžiančias serveriams nurodyti, kuriems kilmės šaltiniams (domenams, schemoms ar prievadams) leidžiama pasiekti jų išteklius. Iš esmės tai sušvelnina tos pačios kilmės politiką konkrečioms skirtingų kilmės šaltinių užklausoms, įgalindama teisėtą komunikaciją, kartu apsaugant nuo kenkėjiškų atakų.
CORS veikia pridedant naujas HTTP antraštes, kurios nurodo leidžiamus kilmės šaltinius ir metodus (pvz., GET, POST, PUT, DELETE), kurie yra leidžiami skirtingų kilmės šaltinių užklausoms. Kai naršyklė pateikia skirtingos kilmės užklausą, ji kartu su užklausa siunčia Origin antraštę. Serveris atsako su Access-Control-Allow-Origin antrašte, kuri nurodo leidžiamą kilmės šaltinį (-ius). Jei užklausos kilmės šaltinis atitinka Access-Control-Allow-Origin antraštės vertę (arba jei vertė yra *), naršyklė leidžia JavaScript kodui pasiekti atsakymą.
Kaip veikia CORS: detalus paaiškinimas
CORS procesas paprastai apima dviejų tipų užklausas:
- Paprastos užklausos (Simple Requests): Tai užklausos, kurios atitinka tam tikrus kriterijus. Jei užklausa atitinka šias sąlygas, naršyklė ją siunčia tiesiogiai.
- Parengiamosios užklausos (Preflighted Requests): Tai sudėtingesnės užklausos, kurios reikalauja, kad naršyklė pirmiausia išsiųstų „parengiamąją“ OPTIONS užklausą į serverį, siekiant nustatyti, ar tikrąją užklausą saugu siųsti.
1. Paprastos užklausos
Užklausa laikoma „paprasta“, jei ji atitinka visas šias sąlygas:
- Metodas yra
GET,HEADarbaPOST. - Jei metodas yra
POST,Content-Typeantraštė yra viena iš šių: application/x-www-form-urlencodedmultipart/form-datatext/plain- Nėra nustatytų jokių pasirinktinių antraščių.
Paprastos užklausos pavyzdys:
GET /resource HTTP/1.1
Origin: http://www.example.com
Serverio atsakymo, leidžiančio kilmės šaltinį, pavyzdys:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Content-Type: application/json
{
"data": "Some data"
}
Jei Access-Control-Allow-Origin antraštė yra ir jos vertė atitinka užklausos kilmės šaltinį arba yra nustatyta kaip *, naršyklė leidžia scenarijui pasiekti atsakymo duomenis. Priešingu atveju naršyklė blokuoja prieigą prie atsakymo, o konsolėje rodomas klaidos pranešimas.
2. Parengiamosios užklausos
Užklausa laikoma „parengiamąja“, jei ji neatitinka paprastos užklausos kriterijų. Tai paprastai atsitinka, kai užklausa naudoja kitą HTTP metodą (pvz., PUT, DELETE), nustato pasirinktines antraštes arba naudoja kitą Content-Type nei leidžiamos vertės.
Prieš siunčiant tikrąją užklausą, naršyklė pirmiausia siunčia OPTIONS užklausą serveriui. Ši „parengiamoji“ užklausa apima šias antraštes:
Origin: Užklausą pateikiančio puslapio kilmės šaltinis.Access-Control-Request-Method: HTTP metodas, kuris bus naudojamas tikrojoje užklausoje (pvz.,PUT,DELETE).Access-Control-Request-Headers: Kableliais atskirtas pasirinktinių antraščių, kurios bus siunčiamos tikrojoje užklausoje, sąrašas.
Parengiamosios užklausos pavyzdys:
OPTIONS /resource HTTP/1.1
Origin: http://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header, Content-Type
Serveris turi atsakyti į OPTIONS užklausą su šiomis antraštėmis:
Access-Control-Allow-Origin: Kilmės šaltinis, kuriam leidžiama pateikti užklausą (arba*, leidžiantis bet kurį kilmės šaltinį).Access-Control-Allow-Methods: Kableliais atskirtas HTTP metodų, kurie leidžiami skirtingų kilmės šaltinių užklausoms, sąrašas (pvz.,GET,POST,PUT,DELETE).Access-Control-Allow-Headers: Kableliais atskirtas pasirinktinių antraščių, kurias leidžiama siųsti užklausoje, sąrašas.Access-Control-Max-Age: Sekundžių skaičius, kiek laiko naršyklė gali talpinti parengiamosios užklausos atsakymą talpykloje.
Serverio atsakymo į parengiamąją užklausą pavyzdys:
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
Jei serverio atsakymas į parengiamąją užklausą rodo, kad tikroji užklausa yra leidžiama, naršyklė išsiųs tikrąją užklausą. Priešingu atveju naršyklė blokuos užklausą ir parodys klaidos pranešimą.
CORS įgyvendinimas serverio pusėje
CORS pirmiausia įgyvendinamas serverio pusėje, nustatant atitinkamas HTTP antraštes atsakyme. Konkrečios įgyvendinimo detalės skirsis priklausomai nuo naudojamos serverio pusės technologijos.
Pavyzdys naudojant Node.js su Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Įjungti CORS visiems kilmės šaltiniams
app.use(cors());
// Arba konfigūruoti CORS konkretiems kilmės šaltiniams
// 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('Server listening on port 3000');
});
cors tarpinė programinė įranga (middleware) supaprastina CORS antraščių nustatymo procesą Express sistemoje. Galite įjungti CORS visiems kilmės šaltiniams naudodami cors() arba konfigūruoti jį konkretiems kilmės šaltiniams naudodami cors(corsOptions).
Pavyzdys naudojant Python su Flask:
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)
flask_cors plėtinys suteikia paprastą būdą įjungti CORS Flask programose. Galite įjungti CORS visiems kilmės šaltiniams, perduodami app į CORS(). Taip pat galima konfigūruoti konkrečius kilmės šaltinius.
Pavyzdys naudojant Java su 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);
}
}
Spring Boot sistemoje galite konfigūruoti CORS naudodami WebMvcConfigurer. Tai leidžia smulkmeniškai valdyti leidžiamus kilmės šaltinius, metodus, antraštes ir kitus CORS nustatymus.
CORS antraščių nustatymas tiesiogiai (Bendras pavyzdys)
Jei nenaudojate jokios sistemos, galite nustatyti antraštes tiesiogiai savo serverio pusės kode (pvz., PHP, Ruby on Rails ir t. t.):
CORS geriausios praktikos
Siekiant užtikrinti saugią ir efektyvią komunikaciją tarp skirtingų kilmės šaltinių, laikykitės šių geriausių praktikų:
- Venkite naudoti
Access-Control-Allow-Origin: *produkcinėje aplinkoje: Leidimas visiems kilmės šaltiniams pasiekti jūsų išteklius gali kelti saugumo riziką. Vietoj to, nurodykite tikslius leidžiamus kilmės šaltinius. - Naudokite HTTPS: Visada naudokite HTTPS tiek užklausą teikiančiam, tiek aptarnaujančiam kilmės šaltiniui, kad apsaugotumėte duomenis perdavimo metu.
- Tikrinkite įvesties duomenis: Visada tikrinkite ir „išvalykite“ duomenis, gautus iš skirtingų kilmės šaltinių užklausų, kad išvengtumėte įterpimo (injection) atakų.
- Įgyvendinkite tinkamą autentifikavimą ir autorizavimą: Užtikrinkite, kad tik autorizuoti vartotojai galėtų pasiekti jautrius išteklius.
- Talpinkite parengiamųjų užklausų atsakymus: Naudokite
Access-Control-Max-Age, kad talpintumėte parengiamųjų užklausų atsakymus ir sumažintumėteOPTIONSužklausų skaičių. - Apsvarstykite galimybę naudoti kredencialus: Jei jūsų API reikalauja autentifikavimo su slapukais (cookies) ar HTTP autentifikavimo, turite nustatyti
Access-Control-Allow-Credentialsantraštę įtrueserveryje ircredentialsparinktį į'include'savo JavaScript kode (pvz., naudojantfetcharXMLHttpRequest). Būkite itin atsargūs naudodami šią parinktį, nes netinkamai tvarkoma ji gali sukelti saugumo pažeidžiamumų. Taip pat, kai Access-Control-Allow-Credentials nustatyta į true, Access-Control-Allow-Origin negali būti nustatyta į „*“. Turite aiškiai nurodyti leidžiamą kilmės šaltinį (-ius). - Reguliariai peržiūrėkite ir atnaujinkite CORS konfigūraciją: Jūsų programai tobulėjant, reguliariai peržiūrėkite ir atnaujinkite savo CORS konfigūraciją, kad užtikrintumėte, jog ji išlieka saugi ir atitinka jūsų poreikius.
- Supraskite skirtingų CORS konfigūracijų pasekmes: Būkite informuoti apie skirtingų CORS konfigūracijų saugumo pasekmes ir pasirinkite jūsų programai tinkamiausią konfigūraciją.
- Testuokite savo CORS įgyvendinimą: Kruopščiai testuokite savo CORS įgyvendinimą, kad įsitikintumėte, jog jis veikia kaip tikėtasi ir nesukelia jokių saugumo pažeidžiamumų. Naudokite naršyklės kūrėjo įrankius tinklo užklausoms ir atsakymams tikrinti bei automatizuotus testavimo įrankius CORS elgsenai patikrinti.
Pavyzdys: Fetch API naudojimas su CORS
Štai pavyzdys, kaip naudoti fetch API, norint pateikti skirtingos kilmės užklausą:
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors', // Nurodo naršyklei, kad tai yra CORS užklausa
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
}
})
.then(response => {
if (!response.ok) {
throw new Error('Tinklo atsakymas nebuvo sėkmingas');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Kilo problema atliekant fetch operaciją:', error);
});
mode: 'cors' parinktis nurodo naršyklei, kad tai yra CORS užklausa. Jei serveris neleidžia kilmės šaltinio, naršyklė blokuos prieigą prie atsakymo ir bus išmesta klaida.
Jei naudojate kredencialus (pvz., slapukus), turite nustatyti credentials parinktį į 'include':
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors',
credentials: 'include', // Įtraukti slapukus į užklausą
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
// ...
});
CORS ir JSONP
JSON su užpildu (JSON with Padding, JSONP) yra senesnė technika, skirta apeiti tos pačios kilmės politiką. Ji veikia dinamiškai sukuriant <script> žymę, kuri įkelia duomenis iš kito domeno. Nors JSONP gali būti naudingas tam tikrose situacijose, jis turi didelių saugumo apribojimų ir, jei įmanoma, jo reikėtų vengti. CORS yra pageidaujamas sprendimas komunikacijai tarp skirtingų kilmės šaltinių, nes jis suteikia saugesnį ir lankstesnį mechanizmą.
Pagrindiniai skirtumai tarp CORS ir JSONP:
- Saugumas: CORS yra saugesnis nei JSONP, nes leidžia serveriui kontroliuoti, kuriems kilmės šaltiniams leidžiama pasiekti jo išteklius. JSONP nesuteikia jokios kilmės šaltinio kontrolės.
- HTTP metodai: CORS palaiko visus HTTP metodus (pvz.,
GET,POST,PUT,DELETE), o JSONP palaiko tikGETužklausas. - Klaidų tvarkymas: CORS suteikia geresnį klaidų tvarkymą nei JSONP. Kai CORS užklausa nepavyksta, naršyklė pateikia išsamius klaidų pranešimus. JSONP klaidų tvarkymas apsiriboja tik nustatymu, ar scenarijus buvo sėkmingai įkeltas.
CORS problemų sprendimas
CORS problemų derinimas gali būti varginantis. Štai keletas įprastų problemų sprendimo patarimų:
- Patikrinkite naršyklės konsolę: Naršyklės konsolė paprastai pateikia išsamius klaidų pranešimus apie CORS problemas.
- Išnagrinėkite tinklo užklausas: Naudokite naršyklės kūrėjo įrankius, kad išnagrinėtumėte tiek užklausos, tiek atsakymo HTTP antraštes. Patikrinkite, ar
OriginirAccess-Control-Allow-Originantraštės yra nustatytos teisingai. - Patikrinkite serverio pusės konfigūraciją: Dar kartą patikrinkite savo serverio pusės CORS konfigūraciją, kad įsitikintumėte, jog ji leidžia teisingus kilmės šaltinius, metodus ir antraštes.
- Išvalykite naršyklės talpyklą: Kartais talpykloje išsaugoti parengiamųjų užklausų atsakymai gali sukelti CORS problemų. Pabandykite išvalyti naršyklės talpyklą arba naudoti privataus naršymo langą.
- Naudokite CORS tarpinį serverį (proxy): Kai kuriais atvejais gali prireikti naudoti CORS tarpinį serverį, kad apeitumėte CORS apribojimus. Tačiau atminkite, kad CORS tarpinio serverio naudojimas gali kelti saugumo rizikų.
- Ieškokite konfigūracijos klaidų: Ieškokite įprastų konfigūracijos klaidų, tokių kaip trūkstama
Access-Control-Allow-Originantraštė, neteisingosAccess-Control-Allow-MethodsarAccess-Control-Allow-Headersvertės, arba neteisingaOriginantraštė užklausoje.
Išvada
Skirtingų kilmės šaltinių išteklių bendrinimas (CORS) yra esminis mechanizmas, leidžiantis saugią komunikaciją tarp skirtingų kilmės šaltinių JavaScript programose. Suprasdami tos pačios kilmės politiką, CORS veikimo principus ir įvairias susijusias HTTP antraštes, kūrėjai gali efektyviai įgyvendinti CORS, kad apsaugotų savo programas nuo saugumo pažeidžiamumų, kartu leisdami teisėtas skirtingų kilmės šaltinių užklausas. Geriausių CORS konfigūravimo praktikų laikymasis ir reguliarus įgyvendinimo peržiūrėjimas yra labai svarbūs norint palaikyti saugią ir patikimą interneto programą.
Šis išsamus vadovas suteikia tvirtą pagrindą suprasti ir įgyvendinti CORS. Nepamirškite pasikonsultuoti su oficialia dokumentacija ir ištekliais, skirtais jūsų konkrečiai serverio pusės technologijai, kad užtikrintumėte teisingą ir saugų CORS įgyvendinimą.