En omfattende guide til å forstå og implementere Cross-Origin Resource Sharing (CORS) for sikker JavaScript-kommunikasjon mellom ulike domener.
Implementering av kryss-opprinnelse sikkerhet: Beste praksis for JavaScript-kommunikasjon
I dagens sammenkoblede web må JavaScript-applikasjoner ofte samhandle med ressurser fra ulike opprinnelser (domener, protokoller eller porter). Denne interaksjonen styres av nettleserens Same-Origin Policy, en avgjørende sikkerhetsmekanisme designet for å forhindre ondsinnede skript fra å få tilgang til sensitive data på tvers av domenegrenser. Imidlertid er legitim kommunikasjon på tvers av opprinnelser ofte nødvendig. Det er her Cross-Origin Resource Sharing (CORS) kommer inn. Denne artikkelen gir en omfattende oversikt over CORS, implementeringen av det, og beste praksis for sikker kommunikasjon på tvers av opprinnelser i JavaScript.
Forståelse av Same-Origin Policy
Same-Origin Policy (SOP) er et fundamentalt sikkerhetskonsept i nettlesere. Det begrenser skript som kjører på én opprinnelse fra å få tilgang til ressurser fra en annen opprinnelse. En opprinnelse er definert av kombinasjonen av protokoll (f.eks. HTTP eller HTTPS), domenenavn (f.eks. example.com) og portnummer (f.eks. 80 eller 443). To URL-er har samme opprinnelse bare hvis alle tre komponentene stemmer nøyaktig overens.
For eksempel:
http://www.example.comoghttp://www.example.com/path: Samme opprinnelsehttp://www.example.comoghttps://www.example.com: Ulik opprinnelse (ulik protokoll)http://www.example.comoghttp://subdomain.example.com: Ulik opprinnelse (ulikt domene)http://www.example.com:80oghttp://www.example.com:8080: Ulik opprinnelse (ulik port)
SOP er et kritisk forsvar mot Cross-Site Scripting (XSS)-angrep, der ondsinnede skript som er injisert på et nettsted kan stjele brukerdata eller utføre uautoriserte handlinger på vegne av brukeren.
Hva er Cross-Origin Resource Sharing (CORS)?
CORS er en mekanisme som bruker HTTP-headere for å la servere angi hvilke opprinnelser (domener, skjemaer eller porter) som har tillatelse til å få tilgang til deres ressurser. Det letter i hovedsak på Same-Origin Policy for spesifikke forespørsler på tvers av opprinnelser, noe som muliggjør legitim kommunikasjon samtidig som det beskytter mot ondsinnede angrep.
CORS fungerer ved å legge til nye HTTP-headere som spesifiserer de tillatte opprinnelsene og metodene (f.eks. GET, POST, PUT, DELETE) som er tillatt for forespørsler på tvers av opprinnelser. Når en nettleser gjør en forespørsel på tvers av opprinnelser, sender den en Origin-header med forespørselen. Serveren svarer med en Access-Control-Allow-Origin-header som spesifiserer den/de tillatte opprinnelsen(e). Hvis opprinnelsen til forespørselen samsvarer med verdien i Access-Control-Allow-Origin-headeren (eller hvis verdien er *), tillater nettleseren JavaScript-koden å få tilgang til svaret.
Hvordan CORS fungerer: En detaljert forklaring
CORS-prosessen involverer vanligvis to typer forespørsler:
- Enkle forespørsler: Dette er forespørsler som oppfyller spesifikke kriterier. Hvis en forespørsel oppfyller disse betingelsene, sender nettleseren forespørselen direkte.
- Preflight-forespørsler: Dette er mer komplekse forespørsler som krever at nettleseren først sender en "preflight" OPTIONS-forespørsel til serveren for å avgjøre om den faktiske forespørselen er trygg å sende.
1. Enkle forespørsler
En forespørsel anses som "enkel" hvis den oppfyller alle følgende betingelser:
- Metoden er
GET,HEADellerPOST. - Hvis metoden er
POST, erContent-Type-headeren en av følgende: application/x-www-form-urlencodedmultipart/form-datatext/plain- Ingen egendefinerte headere er satt.
Eksempel på en enkel forespørsel:
GET /resource HTTP/1.1
Origin: http://www.example.com
Eksempel på et serversvar som tillater opprinnelsen:
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 verdien samsvarer med forespørselens opprinnelse eller er satt til *, lar nettleseren skriptet få tilgang til svardataene. Ellers blokkerer nettleseren tilgangen til svaret, og en feilmelding vises i konsollen.
2. Preflight-forespørsler
En forespørsel anses som "preflighted" hvis den ikke oppfyller kriteriene for en enkel forespørsel. Dette skjer vanligvis når forespørselen bruker en annen HTTP-metode (f.eks. PUT, DELETE), setter egendefinerte headere, eller bruker en annen Content-Type enn de tillatte verdiene.
Før den faktiske forespørselen sendes, sender nettleseren først en OPTIONS-forespørsel til serveren. Denne "preflight"-forespørselen inkluderer følgende headere:
Origin: Opprinnelsen til siden som sender forespørselen.Access-Control-Request-Method: HTTP-metoden som vil bli brukt i den faktiske forespørselen (f.eks.PUT,DELETE).Access-Control-Request-Headers: En kommadelt liste over de egendefinerte headerne som vil bli sendt i den faktiske forespørselen.
Eksempel på en preflight-forespørsel:
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 må svare på OPTIONS-forespørselen med følgende headere:
Access-Control-Allow-Origin: Opprinnelsen som har lov til å gjøre forespørselen (eller*for å tillate enhver opprinnelse).Access-Control-Allow-Methods: En kommadelt liste over HTTP-metoder som er tillatt for forespørsler på tvers av opprinnelser (f.eks.GET,POST,PUT,DELETE).Access-Control-Allow-Headers: En kommadelt liste over de egendefinerte headerne som er tillatt å bli sendt i forespørselen.Access-Control-Max-Age: Antall sekunder preflight-svaret kan caches av nettleseren.
Eksempel på et serversvar på en preflight-forespørsel:
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-forespørselen indikerer at den faktiske forespørselen er tillatt, vil nettleseren deretter sende den faktiske forespørselen. Ellers vil nettleseren blokkere forespørselen og vise en feilmelding.
Implementering av CORS på serversiden
CORS implementeres primært på serversiden ved å sette de riktige HTTP-headerne i svaret. De spesifikke implementeringsdetaljene vil variere avhengig av server-side-teknologien som brukes.
Eksempel med Node.js og Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Aktiver CORS for alle opprinnelser
app.use(cors());
// Alternativt, konfigurer CORS for spesifikke opprinnelser
// 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 prosessen med å sette CORS-headere i Express. Du kan aktivere CORS for alle opprinnelser ved å bruke `cors()` eller konfigurere det for spesifikke opprinnelser med `cors(corsOptions)`.
Eksempel med Python og 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`-utvidelsen gir en enkel måte å aktivere CORS i Flask-applikasjoner. Du kan aktivere CORS for alle opprinnelser ved å sende `app` til `CORS()`. Konfigurasjon for spesifikke opprinnelser er også mulig.
Eksempel med Java og 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 hjelp av en `WebMvcConfigurer`. Dette gir finkornet kontroll over tillatte opprinnelser, metoder, headere og andre CORS-innstillinger.
Sette CORS-headere direkte (Generisk eksempel)
Hvis du ikke bruker et rammeverk, kan du sette headere direkte i server-side-koden din (f.eks. PHP, Ruby on Rails, etc.):
Beste praksis for CORS
For å sikre trygg og effektiv kommunikasjon på tvers av opprinnelser, følg disse beste praksisene:
- Unngå å bruke
Access-Control-Allow-Origin: *i produksjon: Å la alle opprinnelser få tilgang til ressursene dine kan være en sikkerhetsrisiko. Spesifiser i stedet de nøyaktige opprinnelsene som er tillatt. - Bruk HTTPS: Bruk alltid HTTPS for både den forespørrende og den serverende opprinnelsen for å beskytte data under overføring.
- Valider input: Valider og rens alltid data mottatt fra forespørsler på tvers av opprinnelser for å forhindre injeksjonsangrep.
- Implementer korrekt autentisering og autorisasjon: Sørg for at kun autoriserte brukere har tilgang til sensitive ressurser.
- Cache preflight-svar: Bruk
Access-Control-Max-Agefor å cache preflight-svar og redusere antallOPTIONS-forespørsler. - Vurder å bruke legitimasjon (credentials): Hvis API-et ditt krever autentisering med informasjonskapsler eller HTTP-autentisering, må du sette
Access-Control-Allow-Credentials-headeren tiltruepå serveren ogcredentials-alternativet til'include'i JavaScript-koden din (f.eks. ved bruk avfetchellerXMLHttpRequest). Vær ekstremt forsiktig når du bruker dette alternativet, da det kan introdusere sikkerhetssårbarheter hvis det ikke håndteres riktig. Også, når Access-Control-Allow-Credentials er satt til true, kan ikke Access-Control-Allow-Origin settes til "*". Du må eksplisitt spesifisere de(n) tillatte opprinnelsen(e). - Gjennomgå og oppdater CORS-konfigurasjonen regelmessig: Etter hvert som applikasjonen din utvikler seg, bør du jevnlig gjennomgå og oppdatere CORS-konfigurasjonen for å sikre at den forblir sikker og dekker dine behov.
- Forstå implikasjonene av ulike CORS-konfigurasjoner: Vær klar over sikkerhetsimplikasjonene av forskjellige CORS-konfigurasjoner og velg den konfigurasjonen som passer for din applikasjon.
- Test CORS-implementeringen din: Test CORS-implementeringen din grundig for å sikre at den fungerer som forventet og ikke introduserer noen sikkerhetssårbarheter. Bruk nettleserens utviklerverktøy for å inspisere nettverksforespørsler og -svar, og bruk automatiserte testverktøy for å verifisere CORS-atferd.
Eksempel: Bruk av Fetch API med CORS
Her er et eksempel på hvordan du bruker fetch-API-et for å gjøre en forespørsel på tvers av opprinnelser:
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors', // Forteller nettleseren at dette er en CORS-forespørsel
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'-alternativet forteller nettleseren at dette er en CORS-forespørsel. Hvis serveren ikke tillater opprinnelsen, vil nettleseren blokkere tilgangen til svaret, og en feil vil bli kastet.
Hvis du bruker legitimasjon (f.eks. informasjonskapsler), må du sette credentials-alternativet til 'include':
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors',
credentials: 'include', // Inkluder informasjonskapsler i forespørselen
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
// ...
});
CORS og JSONP
JSON with Padding (JSONP) er en eldre teknikk for å omgå Same-Origin Policy. Den fungerer ved å dynamisk opprette en <script>-tag som laster data fra et annet domene. Selv om JSONP kan være nyttig i visse situasjoner, har den betydelige sikkerhetsbegrensninger og bør unngås når det er mulig. CORS er den foretrukne løsningen for kommunikasjon på tvers av opprinnelser fordi den gir en sikrere og mer fleksibel mekanisme.
Hovedforskjeller mellom CORS og JSONP:
- Sikkerhet: CORS er sikrere enn JSONP fordi det lar serveren kontrollere hvilke opprinnelser som har lov til å få tilgang til ressursene. JSONP gir ingen opprinnelseskontroll.
- HTTP-metoder: CORS støtter alle HTTP-metoder (f.eks.
GET,POST,PUT,DELETE), mens JSONP kun støtterGET-forespørsler. - Feilhåndtering: CORS gir bedre feilhåndtering enn JSONP. Når en CORS-forespørsel mislykkes, gir nettleseren detaljerte feilmeldinger. JSONPs feilhåndtering er begrenset til å oppdage om skriptet ble lastet inn vellykket.
Feilsøking av CORS-problemer
CORS-problemer kan være frustrerende å feilsøke. Her er noen vanlige feilsøkingstips:
- Sjekk nettleserkonsollen: Nettleserkonsollen vil vanligvis gi detaljerte feilmeldinger om CORS-problemer.
- Inspiser nettverksforespørsler: Bruk nettleserens utviklerverktøy for å inspisere HTTP-headerne for både forespørselen og svaret. Verifiser at
Origin- ogAccess-Control-Allow-Origin-headerne er satt riktig. - Verifiser server-side-konfigurasjonen: Dobbeltsjekk CORS-konfigurasjonen på serversiden for å sikre at den tillater de riktige opprinnelsene, metodene og headerne.
- Tøm nettleserens cache: Noen ganger kan cachede preflight-svar forårsake CORS-problemer. Prøv å tømme nettleserens cache eller bruk et privat nettleservindu.
- Bruk en CORS-proxy: I noen tilfeller kan det være nødvendig å bruke en CORS-proxy for å omgå CORS-restriksjoner. Vær imidlertid klar over at bruk av en CORS-proxy kan introdusere sikkerhetsrisikoer.
- Se etter feilkonfigurasjoner: Se etter vanlige feilkonfigurasjoner som en manglende
Access-Control-Allow-Origin-header, feil verdier forAccess-Control-Allow-MethodsellerAccess-Control-Allow-Headers, eller en feilaktigOrigin-header i forespørselen.
Konklusjon
Cross-Origin Resource Sharing (CORS) er en essensiell mekanisme for å muliggjøre sikker kommunikasjon på tvers av opprinnelser i JavaScript-applikasjoner. Ved å forstå Same-Origin Policy, CORS-arbeidsflyten og de ulike involverte HTTP-headerne, kan utviklere implementere CORS effektivt for å beskytte applikasjonene sine mot sikkerhetssårbarheter samtidig som de tillater legitime forespørsler på tvers av opprinnelser. Å følge beste praksis for CORS-konfigurasjon og jevnlig gjennomgang av implementeringen er avgjørende for å opprettholde en sikker og robust webapplikasjon.
Denne omfattende guiden gir et solid grunnlag for å forstå og implementere CORS. Husk å konsultere den offisielle dokumentasjonen og ressursene for din spesifikke server-side-teknologi for å sikre at du implementerer CORS korrekt og sikkert.