En omfattende guide til at forstå og implementere Cross-Origin Resource Sharing (CORS) for sikker JavaScript-kommunikation mellem forskellige domæner.
Implementering af Cross-Origin-sikkerhed: Bedste praksis for JavaScript-kommunikation
I nutidens forbundne web har JavaScript-applikationer ofte brug for at interagere med ressourcer fra forskellige oprindelser (domæner, protokoller eller porte). Denne interaktion er styret af browserens Same-Origin Policy, en afgørende sikkerhedsmekanisme designet til at forhindre ondsindede scripts i at få adgang til følsomme data på tværs af domænegrænser. Men legitim kommunikation på tværs af oprindelser er ofte nødvendig. Det er her, Cross-Origin Resource Sharing (CORS) kommer ind i billedet. Denne artikel giver en omfattende oversigt over CORS, dets implementering og bedste praksis for sikker kommunikation på tværs af oprindelser i JavaScript.
Forståelse af Same-Origin Policy
Same-Origin Policy (SOP) er et grundlæggende sikkerhedskoncept i webbrowsere. Det begrænser scripts, der kører på én oprindelse, i at få adgang til ressourcer fra en anden oprindelse. En oprindelse er defineret af kombinationen af protokollen (f.eks. HTTP eller HTTPS), domænenavnet (f.eks. example.com) og portnummeret (f.eks. 80 eller 443). To URL'er har samme oprindelse, kun hvis alle tre komponenter matcher præcist.
For eksempel:
http://www.example.comoghttp://www.example.com/path: Samme oprindelsehttp://www.example.comoghttps://www.example.com: Forskellig oprindelse (forskellig protokol)http://www.example.comoghttp://subdomain.example.com: Forskellig oprindelse (forskelligt domæne)http://www.example.com:80oghttp://www.example.com:8080: Forskellig oprindelse (forskellig port)
SOP er et kritisk forsvar mod Cross-Site Scripting (XSS)-angreb, hvor ondsindede scripts, der er injiceret på en hjemmeside, kan stjæle brugerdata eller udføre uautoriserede handlinger på vegne af brugeren.
Hvad er Cross-Origin Resource Sharing (CORS)?
CORS er en mekanisme, der bruger HTTP-headere til at give servere mulighed for at angive, hvilke oprindelser (domæner, skemaer eller porte) der har tilladelse til at få adgang til deres ressourcer. Det letter i bund og grund Same-Origin Policy for specifikke anmodninger på tværs af oprindelser, hvilket muliggør legitim kommunikation, mens det stadig beskytter mod ondsindede angreb.
CORS fungerer ved at tilføje nye HTTP-headere, der specificerer de tilladte oprindelser og de metoder (f.eks. GET, POST, PUT, DELETE), der er tilladt for anmodninger på tværs af oprindelser. Når en browser foretager en anmodning på tværs af oprindelser, sender den en Origin-header med anmodningen. Serveren svarer med en Access-Control-Allow-Origin-header, der specificerer den/de tilladte oprindelse(r). Hvis anmodningens oprindelse matcher værdien i Access-Control-Allow-Origin-headeren (eller hvis værdien er *), tillader browseren JavaScript-koden at få adgang til svaret.
Hvordan CORS virker: En detaljeret forklaring
CORS-processen involverer typisk to typer anmodninger:
- Simple anmodninger: Disse er anmodninger, der opfylder specifikke kriterier. Hvis en anmodning opfylder disse betingelser, sender browseren anmodningen direkte.
- Preflighted-anmodninger: Disse er mere komplekse anmodninger, der kræver, at browseren først sender en "preflight" OPTIONS-anmodning til serveren for at afgøre, om den faktiske anmodning er sikker at sende.
1. Simple anmodninger
En anmodning betragtes som "simple", hvis den opfylder alle følgende betingelser:
- Metoden er
GET,HEADellerPOST. - Hvis metoden er
POST, erContent-Type-headeren en af følgende: application/x-www-form-urlencodedmultipart/form-datatext/plain- Ingen brugerdefinerede headere er sat.
Eksempel på en simple anmodning:
GET /resource HTTP/1.1
Origin: http://www.example.com
Eksempel på et serversvar, der tillader oprindelsen:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Content-Type: application/json
{
"data": "Some data"
}
Hvis Access-Control-Allow-Origin-headeren er til stede, og dens værdi matcher anmodningens oprindelse eller er sat til *, tillader browseren scriptet at få adgang til svardataene. Ellers blokerer browseren adgangen til svaret, og en fejlmeddelelse vises i konsollen.
2. Preflighted-anmodninger
En anmodning betragtes som "preflighted", hvis den ikke opfylder kriterierne for en simple anmodning. Dette sker typisk, når anmodningen bruger en anden HTTP-metode (f.eks. PUT, DELETE), sætter brugerdefinerede headere eller bruger en Content-Type, der er anderledes end de tilladte værdier.
Før den faktiske anmodning sendes, sender browseren først en OPTIONS-anmodning til serveren. Denne "preflight"-anmodning inkluderer følgende headere:
Origin: Oprindelsen for den anmodende side.Access-Control-Request-Method: Den HTTP-metode, der vil blive brugt i den faktiske anmodning (f.eks.PUT,DELETE).Access-Control-Request-Headers: En kommasepareret liste over de brugerdefinerede headere, der vil blive sendt i den faktiske anmodning.
Eksempel på en preflight-anmodning:
OPTIONS /resource HTTP/1.1
Origin: http://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header, Content-Type
Serveren skal svare på OPTIONS-anmodningen med følgende headere:
Access-Control-Allow-Origin: Den oprindelse, der har tilladelse til at foretage anmodningen (eller*for at tillade enhver oprindelse).Access-Control-Allow-Methods: En kommasepareret liste over HTTP-metoder, der er tilladt for anmodninger på tværs af oprindelser (f.eks.GET,POST,PUT,DELETE).Access-Control-Allow-Headers: En kommasepareret liste over de brugerdefinerede headere, der er tilladt at blive sendt i anmodningen.Access-Control-Max-Age: Antallet af sekunder, som preflight-svaret kan caches af browseren.
Eksempel på et serversvar på en preflight-anmodning:
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
Hvis serverens svar på preflight-anmodningen indikerer, at den faktiske anmodning er tilladt, vil browseren derefter sende den faktiske anmodning. Ellers vil browseren blokere anmodningen og vise en fejlmeddelelse.
Implementering af CORS på serversiden
CORS implementeres primært på serversiden ved at sætte de passende HTTP-headere i svaret. De specifikke implementeringsdetaljer vil variere afhængigt af den anvendte server-side-teknologi.
Eksempel med Node.js med Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Aktiver CORS for alle oprindelser
app.use(cors());
// Alternativt kan du konfigurere CORS for specifikke oprindelser
// 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-middlewaren forenkler processen med at sætte CORS-headere i Express. Du kan aktivere CORS for alle oprindelser ved at bruge cors() eller konfigurere det for specifikke oprindelser ved hjælp af cors(corsOptions).
Eksempel med Python med 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-udvidelsen giver en simpel måde at aktivere CORS i Flask-applikationer. Du kan aktivere CORS for alle oprindelser ved at sende app til CORS(). Konfiguration for specifikke oprindelser er også mulig.
Eksempel med Java med 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);
}
}
I Spring Boot kan du konfigurere CORS ved hjælp af en WebMvcConfigurer. Dette giver finkornet kontrol over tilladte oprindelser, metoder, headere og andre CORS-indstillinger.
Indstilling af CORS-headere direkte (Generisk eksempel)
Hvis du ikke bruger et framework, kan du sætte headere direkte i din server-side-kode (f.eks. PHP, Ruby on Rails, etc.):
Bedste praksis for CORS
For at sikre sikker og effektiv kommunikation på tværs af oprindelser, følg disse bedste praksis:
- Undgå at bruge
Access-Control-Allow-Origin: *i produktion: At tillade alle oprindelser at få adgang til dine ressourcer kan være en sikkerhedsrisiko. Angiv i stedet de præcise oprindelser, der er tilladt. - Brug HTTPS: Brug altid HTTPS for både den anmodende og den serverende oprindelse for at beskytte data under overførsel.
- Valider input: Valider og rens altid data modtaget fra anmodninger på tværs af oprindelser for at forhindre injektionsangreb.
- Implementer korrekt autentificering og autorisation: Sørg for, at kun autoriserede brugere kan få adgang til følsomme ressourcer.
- Cache preflight-svar: Brug
Access-Control-Max-Agetil at cache preflight-svar og reducere antallet afOPTIONS-anmodninger. - Overvej at bruge legitimationsoplysninger: Hvis dit API kræver godkendelse med cookies eller HTTP-autentificering, skal du sætte
Access-Control-Allow-Credentials-headeren tiltruepå serveren ogcredentials-indstillingen til'include'i din JavaScript-kode (f.eks. når du brugerfetchellerXMLHttpRequest). Vær ekstremt forsigtig, når du bruger denne mulighed, da den kan introducere sikkerhedssårbarheder, hvis den ikke håndteres korrekt. Når Access-Control-Allow-Credentials er sat til true, kan Access-Control-Allow-Origin desuden ikke sættes til "*". Du skal eksplicit angive den/de tilladte oprindelse(r). - Gennemgå og opdater jævnligt CORS-konfigurationen: Efterhånden som din applikation udvikler sig, skal du regelmæssigt gennemgå og opdatere din CORS-konfiguration for at sikre, at den forbliver sikker og opfylder dine behov.
- Forstå implikationerne af forskellige CORS-konfigurationer: Vær opmærksom på sikkerhedsimplikationerne af forskellige CORS-konfigurationer og vælg den konfiguration, der passer til din applikation.
- Test din CORS-implementering: Test din CORS-implementering grundigt for at sikre, at den fungerer som forventet, og at den ikke introducerer nogen sikkerhedssårbarheder. Brug browserens udviklerværktøjer til at inspicere netværksanmodninger og -svar, og brug automatiserede testværktøjer til at verificere CORS-adfærd.
Eksempel: Brug af Fetch API med CORS
Her er et eksempel på, hvordan du bruger fetch-API'en til at foretage en anmodning på tværs af oprindelser:
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors', // Fortæller browseren, at dette er en CORS-anmodning
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
}
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
mode: 'cors'-indstillingen fortæller browseren, at dette er en CORS-anmodning. Hvis serveren ikke tillader oprindelsen, vil browseren blokere adgang til svaret, og en fejl vil blive kastet.
Hvis du bruger legitimationsoplysninger (f.eks. cookies), skal du sætte credentials-indstillingen til 'include':
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors',
credentials: 'include', // Inkluder cookies i anmodningen
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
// ...
});
CORS og JSONP
JSON with Padding (JSONP) er en ældre teknik til at omgå Same-Origin Policy. Den virker ved dynamisk at oprette et <script>-tag, der indlæser data fra et andet domæne. Selvom JSONP kan være nyttigt i visse situationer, har det betydelige sikkerhedsbegrænsninger og bør undgås, når det er muligt. CORS er den foretrukne løsning for kommunikation på tværs af oprindelser, fordi det giver en mere sikker og fleksibel mekanisme.
Væsentlige forskelle mellem CORS og JSONP:
- Sikkerhed: CORS er mere sikkert end JSONP, fordi det giver serveren mulighed for at kontrollere, hvilke oprindelser der har tilladelse til at få adgang til dens ressourcer. JSONP giver ingen oprindelseskontrol.
- HTTP-metoder: CORS understøtter alle HTTP-metoder (f.eks.
GET,POST,PUT,DELETE), mens JSONP kun understøtterGET-anmodninger. - Fejlhåndtering: CORS giver bedre fejlhåndtering end JSONP. Når en CORS-anmodning mislykkes, giver browseren detaljerede fejlmeddelelser. JSONP-fejlhåndtering er begrænset til at opdage, om scriptet blev indlæst med succes.
Fejlfinding af CORS-problemer
CORS-problemer kan være frustrerende at fejlfinde. Her er nogle almindelige fejlfindingstips:
- Tjek browserkonsollen: Browserkonsollen vil normalt give detaljerede fejlmeddelelser om CORS-problemer.
- Inspicer netværksanmodninger: Brug browserens udviklerværktøjer til at inspicere HTTP-headerne for både anmodningen og svaret. Verificer, at
Origin- ogAccess-Control-Allow-Origin-headerne er sat korrekt. - Verificer server-side-konfigurationen: Dobbelttjek din server-side CORS-konfiguration for at sikre, at den tillader de korrekte oprindelser, metoder og headere.
- Ryd browserens cache: Nogle gange kan cachede preflight-svar forårsage CORS-problemer. Prøv at rydde din browsers cache eller bruge et privat browsing-vindue.
- Brug en CORS-proxy: I nogle tilfælde kan det være nødvendigt at bruge en CORS-proxy for at omgå CORS-restriktioner. Vær dog opmærksom på, at brug af en CORS-proxy kan introducere sikkerhedsrisici.
- Tjek for fejlkonfigurationer: Se efter almindelige fejlkonfigurationer såsom en manglende
Access-Control-Allow-Origin-header, ukorrekteAccess-Control-Allow-Methods- ellerAccess-Control-Allow-Headers-værdier, eller en forkertOrigin-header i anmodningen.
Konklusion
Cross-Origin Resource Sharing (CORS) er en essentiel mekanisme til at muliggøre sikker kommunikation på tværs af oprindelser i JavaScript-applikationer. Ved at forstå Same-Origin Policy, CORS-arbejdsgangen og de forskellige involverede HTTP-headere kan udviklere implementere CORS effektivt for at beskytte deres applikationer mod sikkerhedssårbarheder, samtidig med at de tillader legitime anmodninger på tværs af oprindelser. At følge bedste praksis for CORS-konfiguration og regelmæssigt gennemgå din implementering er afgørende for at opretholde en sikker og robust webapplikation.
Denne omfattende guide giver et solidt fundament for at forstå og implementere CORS. Husk at konsultere den officielle dokumentation og ressourcer for din specifikke server-side-teknologi for at sikre, at du implementerer CORS korrekt og sikkert.