Se ti sei imbattuto nell'errore Access to fetch at '...' has been blocked by CORS policy nella console del browser, conosci bene la frustrazione. Gli errori CORS sono tra le problematiche più frequenti nello sviluppo web moderno, eppure il meccanismo sottostante viene spesso frainteso. Questa guida approfondisce il funzionamento del CORS per aiutarti a risolvere i blocchi e comprendere le ragioni di sicurezza dietro questo protocollo.

Che cos'è la Same-Origin Policy (SOP)?

I browser applicano una politica di sicurezza fondamentale chiamata Same-Origin Policy (SOP). Due URL sono considerati della "stessa origine" solo se condividono identico protocollo, hostname e porta.

Confronto tra Origini
https://example.com/pagina1  →  https://example.com/pagina2     ✅ Stessa origine
https://example.com          →  http://example.com             ❌ Protocollo diverso
https://example.com          →  https://api.example.com        ❌ Hostname diverso
https://example.com          →  https://example.com:8080       ❌ Porta diversa

La SOP impedisce a un sito malevolo di leggere dati riservati da un altro sito. Senza questa protezione, qualsiasi sito potrebbe effettuare chiamate all'API della tua banca utilizzando i cookie salvati nel tuo browser.

Cos'è il CORS?

Il CORS (Cross-Origin Resource Sharing) è un meccanismo che allenta le restrizioni della SOP in modo controllato. Permette al server di dichiarare esplicitamente quali origini esterne sono autorizzate ad accedere alle proprie risorse, utilizzando specifici header HTTP.

Come funziona il CORS

Richieste Semplici (Simple Requests)

Per le richieste GET o POST standard con header limitati, il browser esegue la chiamata direttamente e verifica la presenza degli header di autorizzazione nella risposta:

Richiesta CORS Semplice
// Il browser invia:
GET /api/dati HTTP/1.1
Host: api.example.com
Origin: https://miapp.com

// Il server risponde:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://miapp.com
Content-Type: application/json

{"dati": "..."}

Richieste Preflight (OPTIONS)

Per richieste "non semplici" (che includono metodi come PUT/DELETE, header personalizzati o il tipo JSON), il browser invia prima una richiesta di verifica OPTIONS, detta preflight, per chiedere il permesso al server.

Richiesta Preflight
// 1. Il browser richiede il preflight:
OPTIONS /api/utenti HTTP/1.1
Host: api.example.com
Origin: https://miapp.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Content-Type, Authorization

// 2. Il server risponde indicando cosa è consentito:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://miapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

// 3. Il browser invia la richiesta reale solo se il preflight è positivo

Header CORS Fondamentali

Header Principali
Access-Control-Allow-Origin: https://miapp.com   // Origine autorizzata
Access-Control-Allow-Methods: GET, POST, PUT       // Metodi HTTP consentiti
Access-Control-Allow-Headers: Content-Type, Auth   // Header personalizzati permessi
Access-Control-Allow-Credentials: true             // Abilita cookie/auth
Access-Control-Max-Age: 86400                      // Cache preflight (secondi)
Access-Control-Expose-Headers: X-Request-Id        // Header leggibili via JS

Configurazioni lato Server

Express.js (Node.js)
import cors from 'cors';

app.use(cors({
  origin: ['https://miapp.com', 'https://staging.miapp.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true,
  maxAge: 86400
}));
Nginx
location /api/ {
    add_header Access-Control-Allow-Origin "https://miapp.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE" always;
    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;

    if ($request_method = OPTIONS) {
        return 204;
    }
}
PHP
header("Access-Control-Allow-Origin: https://miapp.com");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

Errori CORS comuni

  • Usare Access-Control-Allow-Origin: * con credenziali: Il browser bloccherà la richiesta. Quando credentials: true, devi specificare un'origine esatta.
  • CORS è una protezione lato browser: Non protegge le tue API da chiamate server-to-server. Implementa sempre l'autenticazione su ogni endpoint.
  • Dimenticare il flag always in Nginx: Senza di esso, gli header CORS mancheranno nelle risposte di errore (4xx, 5xx), causando fallimenti durante il debugging.
  • Ignorare le richieste OPTIONS: Se il server risponde con 404 o 405 alle richieste preflight, l'intera comunicazione verrà interrotta dal browser.

Prova i nostri Strumenti Gratuiti

Codifica URL, decodifica Base64 e formatta i file JSON in un istante.