Una guida completa alla Condivisione delle Risorse tra Origini Diverse (CORS), che tratta configurazione, implicazioni sulla sicurezza e migliori pratiche per gli sviluppatori.
Condivisione delle Risorse tra Origini Diverse (CORS): Configurazione e Migliori Pratiche di Sicurezza
Nel mondo dello sviluppo web, la sicurezza è fondamentale. Un aspetto critico della sicurezza web è la gestione di come le pagine web di un'origine possano accedere a risorse di un'origine diversa. È qui che entra in gioco la Condivisione delle Risorse tra Origini Diverse (CORS). Il CORS è una funzionalità di sicurezza del browser che impedisce alle pagine web di effettuare richieste a un dominio diverso da quello che ha servito la pagina stessa. Questo meccanismo è stato introdotto per prevenire che siti web malevoli accedano a dati sensibili. Questo articolo fornisce una guida completa al CORS, trattando la sua configurazione, le implicazioni sulla sicurezza e le migliori pratiche.
Comprendere la Same-Origin Policy
Il CORS si basa sul fondamento della Same-Origin Policy (Politica della Stessa Origine), un meccanismo di sicurezza fondamentale implementato dai browser web. La same-origin policy impedisce alle pagine web di effettuare richieste a un dominio diverso da quello che ha servito la pagina web. Due URL sono considerati della stessa origine se hanno lo stesso protocollo (es. HTTP o HTTPS), host (es. example.com) e porta (es. 80 o 443). Ad esempio:
http://example.comehttp://example.com/pathsono della stessa origine.http://example.comehttps://example.comsono origini diverse (protocolli diversi).http://example.comehttp://www.example.comsono origini diverse (host diversi).http://example.com:80ehttp://example.com:8080sono origini diverse (porte diverse).
La same-origin policy è progettata per prevenire attacchi di tipo Cross-Site Scripting (XSS), in cui un sito web malevolo inietta script in un sito web affidabile per rubare dati degli utenti o eseguire azioni non autorizzate. Senza la same-origin policy, un sito web malevolo potrebbe potenzialmente accedere alle informazioni del tuo conto bancario se fossi loggato al portale della tua banca online in un'altra scheda.
Cos'è la Condivisione delle Risorse tra Origini Diverse (CORS)?
Sebbene la same-origin policy sia cruciale per la sicurezza, può anche essere restrittiva in scenari legittimi in cui i siti web necessitano di accedere a risorse da origini diverse. Ad esempio, un'applicazione web ospitata su example.com potrebbe dover recuperare dati da un'API ospitata su api.example.net. Il CORS fornisce un meccanismo per aggirare la same-origin policy in modo controllato, consentendo alle pagine web di effettuare richieste cross-origin quando esplicitamente autorizzate dal server.
Il CORS funziona aggiungendo intestazioni HTTP alla risposta del server, indicando quali origini sono autorizzate ad accedere alla risorsa. Il browser quindi controlla queste intestazioni e blocca la richiesta se l'origine della pagina web che effettua la richiesta non è consentita.
Come Funziona il CORS: Le Intestazioni HTTP
Il CORS si basa su specifiche intestazioni HTTP per facilitare le richieste cross-origin. Ecco le principali intestazioni coinvolte:
1. Origin (Intestazione di Richiesta)
L'intestazione Origin viene inviata dal browser nelle richieste cross-origin. Indica l'origine (protocollo, host e porta) della pagina web che effettua la richiesta. Ad esempio:
Origin: http://example.com
2. Access-Control-Allow-Origin (Intestazione di Risposta)
L'intestazione Access-Control-Allow-Origin è l'intestazione più importante nel CORS. Specifica quali origini sono autorizzate ad accedere alla risorsa. Può avere uno dei seguenti valori:
- Un'origine specifica: Ad esempio,
Access-Control-Allow-Origin: http://example.comconsente solo richieste dahttp://example.com. *(wildcard):Access-Control-Allow-Origin: *consente richieste da qualsiasi origine. Questo dovrebbe essere usato con cautela, poiché disabilita di fatto la same-origin policy per quella risorsa.
Esempio:
Access-Control-Allow-Origin: https://www.example.com
3. Access-Control-Allow-Methods (Intestazione di Risposta)
L'intestazione Access-Control-Allow-Methods specifica i metodi HTTP (es. GET, POST, PUT, DELETE) che sono consentiti nella richiesta cross-origin. Questo è richiesto per le richieste preflight (spiegate di seguito).
Esempio:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
4. Access-Control-Allow-Headers (Intestazione di Risposta)
L'intestazione Access-Control-Allow-Headers specifica le intestazioni HTTP che sono consentite nella richiesta cross-origin. Anche questo è richiesto per le richieste preflight.
Esempio:
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
5. Access-Control-Allow-Credentials (Intestazione di Risposta)
L'intestazione Access-Control-Allow-Credentials specifica se il browser debba includere le credenziali (es. cookie, intestazioni di autorizzazione) nella richiesta cross-origin. Può avere uno dei due valori: true o false. Se è impostato su true, l'intestazione Access-Control-Allow-Origin non può essere impostata su *. Deve essere un'origine specifica.
Esempio:
Access-Control-Allow-Credentials: true
6. Access-Control-Max-Age (Intestazione di Risposta)
L'intestazione Access-Control-Max-Age specifica il numero di secondi per cui il browser può memorizzare nella cache i risultati della richiesta preflight. Questo può migliorare le prestazioni riducendo il numero di richieste preflight.
Esempio:
Access-Control-Max-Age: 3600
Richieste Semplici vs. Richieste Preflight
Il CORS distingue tra due tipi di richieste cross-origin: richieste semplici e richieste preflight.
Richieste Semplici
Una richiesta semplice è una richiesta che soddisfa i seguenti criteri:
- Il metodo è
GET,HEADoPOST. - Se il metodo è
POST, l'intestazioneContent-Typeè una delle seguenti:application/x-www-form-urlencoded,multipart/form-dataotext/plain. - La richiesta non imposta alcuna intestazione personalizzata (oltre a quelle impostate automaticamente dal browser).
Per le richieste semplici, il browser invia la richiesta direttamente al server. Il server risponde quindi con le intestazioni CORS appropriate. Se l'origine è consentita, il browser elabora la risposta. Altrimenti, il browser blocca la risposta e genera un errore.
Richieste Preflight
Una richiesta preflight viene inviata dal browser prima di effettuare la richiesta cross-origin effettiva se la richiesta non soddisfa i criteri per una richiesta semplice. Questo accade tipicamente quando la richiesta utilizza un metodo diverso da GET, HEAD o POST, o quando la richiesta imposta intestazioni personalizzate.
La richiesta preflight è una richiesta OPTIONS che include le seguenti intestazioni:
Origin: L'origine della pagina web che effettua la richiesta.Access-Control-Request-Method: Il metodo HTTP che sarà utilizzato nella richiesta effettiva.Access-Control-Request-Headers: Una lista separata da virgole delle intestazioni personalizzate che saranno utilizzate nella richiesta effettiva.
Il server risponde quindi con le seguenti intestazioni:
Access-Control-Allow-Origin: L'origine autorizzata ad accedere alla risorsa.Access-Control-Allow-Methods: I metodi HTTP consentiti nella richiesta cross-origin.Access-Control-Allow-Headers: Le intestazioni HTTP consentite nella richiesta cross-origin.Access-Control-Max-Age: Il numero di secondi per cui il browser può memorizzare nella cache i risultati della richiesta preflight.
Se il server risponde con le intestazioni CORS appropriate, il browser procede con la richiesta cross-origin effettiva. Altrimenti, il browser blocca la richiesta e genera un errore.
Esempi di Configurazione CORS
L'implementazione del CORS varia a seconda della tecnologia lato server che si sta utilizzando. Ecco alcuni esempi per i linguaggi e i framework lato server più comuni:
Node.js con Express
Utilizzare il middleware cors è un approccio comune per configurare il CORS in Node.js con Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Abilita CORS per tutte le origini
app.use(cors());
// Abilita CORS per un'origine specifica
// app.use(cors({ origin: 'http://example.com' }));
// Abilita CORS con opzioni
// app.use(cors({
// origin: ['http://example.com', 'http://localhost:3000'],
// methods: ['GET', 'POST', 'PUT', 'DELETE'],
// allowedHeaders: ['Content-Type', 'Authorization'],
// credentials: true
// }));
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from the API!' });
});
app.listen(3001, () => {
console.log('Server listening on port 3001');
});
Python con Flask
Puoi usare l'estensione Flask-CORS per configurare il CORS in Flask:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
// Abilita CORS per tutte le origini
CORS(app)
// Abilita CORS per origini specifiche
// CORS(app, origins=['http://example.com', 'http://localhost:3000'])
@app.route('/api/data')
def get_data():
return {'message': 'Hello from the API!'}
if __name__ == '__main__':
app.run(port=3001)
Java con Spring Boot
Spring Boot fornisce diversi modi per configurare il CORS. Un approccio è usare l'annotazione @CrossOrigin:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Origine specifica
public class ApiController {
@GetMapping("/api/data")
public String getData() {
return "Hello from the API!";
}
}
// Configurazione CORS globale (usando WebMvcConfigurer):
// @Configuration
// public class CorsConfig implements WebMvcConfigurer {
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedOrigins("http://example.com", "http://localhost:3000")
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// .allowedHeaders("Content-Type", "Authorization")
// .allowCredentials(true)
// .maxAge(3600);
// }
// }
PHP
In PHP, puoi impostare le intestazioni CORS direttamente nel tuo script:
<?php
header("Access-Control-Allow-Origin: http://example.com");
header("Content-Type: application/json");
$data = array("message" => "Hello from the API!");
echo json_encode($data);
?>
Considerazioni sulla Sicurezza del CORS
Sebbene il CORS abiliti le richieste cross-origin, è fondamentale comprendere le implicazioni sulla sicurezza e implementarlo correttamente per evitare vulnerabilità.
1. Evitare di Usare Access-Control-Allow-Origin: * in Produzione
L'uso del carattere jolly * nell'intestazione Access-Control-Allow-Origin consente richieste da qualsiasi origine, disabilitando di fatto la same-origin policy per quella risorsa. Ciò può esporre la tua API a siti web malevoli che possono potenzialmente rubare dati degli utenti o eseguire azioni non autorizzate. Invece, specifica le origini esatte che sono autorizzate ad accedere alla risorsa. Ad esempio, se la tua applicazione web è ospitata su example.com e deve accedere a un'API ospitata su api.example.com, imposta l'intestazione su Access-Control-Allow-Origin: http://example.com.
Esempio globale: Immagina un'API di un servizio finanziario che imposta Access-Control-Allow-Origin: *. Un sito web malevolo potrebbe quindi effettuare richieste a questa API per conto di un utente loggato, trasferendo potenzialmente fondi senza la conoscenza dell'utente.
2. Convalidare l'Intestazione Origin sul Server
Anche se specifichi una lista di origini consentite, è importante convalidare l'intestazione Origin sul server per impedire agli aggressori di falsificare l'origine. Un aggressore potrebbe potenzialmente inviare una richiesta con un'intestazione Origin contraffatta per aggirare i controlli CORS. Per mitigare questo rischio, confronta l'intestazione Origin con una lista di origini fidate lato server. Se l'origine non è nella lista, rifiuta la richiesta.
Esempio globale: Considera una piattaforma di e-commerce. Un aggressore potrebbe tentare di imitare l'Origin di una vetrina legittima per accedere a dati sensibili dei clienti dall'API della piattaforma di e-commerce.
3. Fare Attenzione con Access-Control-Allow-Credentials: true
Se imposti Access-Control-Allow-Credentials: true, l'intestazione Access-Control-Allow-Origin non può essere impostata su *. Deve essere un'origine specifica. Questo perché consentire le credenziali da qualsiasi origine può creare un rischio per la sicurezza, in quanto potrebbe permettere a siti web malevoli di accedere ai dati degli utenti se riescono a indurre un utente a visitare il loro sito mentre è anche loggato al sito di destinazione. Questa impostazione è importante quando si ha a che fare con cookie o intestazioni di autorizzazione.
Esempio globale: Una piattaforma di social media che consente richieste cross-origin con credenziali richiede una gestione attenta per prevenire l'accesso non autorizzato agli account degli utenti.
4. Configurare Correttamente Access-Control-Allow-Methods e Access-Control-Allow-Headers
Consenti solo i metodi e le intestazioni HTTP necessari per le richieste cross-origin. Se hai solo bisogno di consentire richieste GET e POST, non consentire PUT, DELETE o altri metodi. Allo stesso modo, consenti solo le intestazioni specifiche di cui la tua applicazione ha bisogno. Configurazioni eccessivamente permissive possono aumentare il rischio di attacchi.
Esempio Globale: Un sistema CRM dovrebbe esporre solo gli endpoint API e le intestazioni necessari alle integrazioni di terze parti autorizzate, minimizzando la superficie di attacco.
5. Usare HTTPS per una Comunicazione Sicura
Usa sempre HTTPS per una comunicazione sicura tra il browser e il server. HTTPS crittografa i dati trasmessi tra il browser e il server, prevenendo intercettazioni e attacchi man-in-the-middle. L'uso di HTTP può esporre dati sensibili agli aggressori, anche se il CORS è configurato correttamente.
Esempio Globale: Le applicazioni sanitarie devono usare HTTPS per proteggere i dati dei pazienti trasmessi tra origini diverse.
6. Content Security Policy (CSP)
Sebbene non sia direttamente correlata al CORS, la Content Security Policy (CSP) è un altro importante meccanismo di sicurezza che può aiutare a prevenire attacchi XSS. La CSP ti permette di definire una whitelist di fonti da cui il browser è autorizzato a caricare risorse. Questo può aiutare a impedire agli aggressori di iniettare script malevoli nel tuo sito web, anche se riescono a bypassare altre misure di sicurezza.
Esempio globale: Le istituzioni finanziarie spesso impiegano rigide politiche CSP per limitare le fonti di contenuto caricate sui loro portali di online banking, riducendo il rischio di attacchi XSS.
Problemi Comuni del CORS e Risoluzione dei Problemi
Gli errori CORS possono essere frustranti da debuggare. Ecco alcuni problemi comuni e come risolverli:
1. "No 'Access-Control-Allow-Origin' header is present on the requested resource."
Questo è l'errore CORS più comune. Indica che il server non sta restituendo l'intestazione Access-Control-Allow-Origin nella sua risposta. Assicurati che il server sia configurato per inviare le intestazioni CORS corrette per l'origine della pagina web che effettua la richiesta. Controlla due volte il codice lato server e i file di configurazione.
2. "Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
Questo errore indica che la richiesta preflight è fallita. Ciò può accadere se il server non risponde alle richieste OPTIONS o se il server restituisce un codice di stato di errore (es. 404, 500) in risposta alla richiesta preflight. Assicurati che il tuo server sia configurato per gestire le richieste OPTIONS e che restituisca un codice di stato 200 OK.
3. "Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'."
Questo errore si verifica quando si tenta di inviare credenziali (es. cookie) in una richiesta cross-origin e l'intestazione Access-Control-Allow-Origin è impostata su *. Come menzionato in precedenza, non è possibile utilizzare il carattere jolly * quando si inviano credenziali. È necessario specificare l'origine esatta autorizzata ad accedere alla risorsa.
4. Caching del Browser
I browser possono memorizzare nella cache le risposte CORS, il che può portare a comportamenti inaspettati se la configurazione CORS cambia. Per prevenire problemi di caching, imposta l'intestazione Cache-Control nella risposta su no-cache, no-store o max-age=0. Puoi anche usare l'intestazione Access-Control-Max-Age per controllare per quanto tempo il browser memorizza nella cache i risultati della richiesta preflight.
Alternative al CORS
Sebbene il CORS sia il modo standard per abilitare le richieste cross-origin, esistono alcune alternative che si possono considerare in determinati scenari:
1. JSON con Padding (JSONP)
JSONP è una tecnica che utilizza il tag <script> per aggirare la same-origin policy. JSONP funziona racchiudendo i dati JSON in una chiamata a una funzione JavaScript. Il browser esegue quindi la funzione JavaScript, passando i dati JSON come argomento. JSONP è più semplice da implementare rispetto al CORS, ma ha alcune limitazioni. Supporta solo richieste GET ed è meno sicuro del CORS.
2. Reverse Proxy
Un reverse proxy è un server che si interpone tra il tuo server API e inoltra le richieste ad esso. Il reverse proxy può essere configurato per aggiungere le intestazioni CORS necessarie alla risposta, nascondendo di fatto le richieste cross-origin al browser. Questo approccio può essere utile se non hai il controllo sul server API o se vuoi semplificare la configurazione CORS.
Conclusione
La Condivisione delle Risorse tra Origini Diverse (CORS) è un meccanismo di sicurezza cruciale che consente alle pagine web di accedere a risorse da origini diverse in modo controllato. Comprendere come funziona il CORS e implementarlo correttamente è essenziale per costruire applicazioni web sicure e affidabili. Seguendo le migliori pratiche delineate in questo articolo, puoi gestire efficacemente il CORS e proteggere le tue API da accessi non autorizzati.
Ricorda di dare sempre la priorità alla sicurezza durante la configurazione del CORS. Evita di usare caratteri jolly, convalida l'intestazione Origin e usa HTTPS per una comunicazione sicura. Adottando queste precauzioni, puoi garantire che le tue applicazioni web siano protette da attacchi cross-site.
Questa guida completa fornisce una solida base per la comprensione del CORS. Fai sempre riferimento alla documentazione ufficiale della tua specifica tecnologia lato server per le informazioni più aggiornate e le migliori pratiche. Rimani informato sulle minacce alla sicurezza emergenti e adatta di conseguenza la tua configurazione CORS.