Ispettore CORS

Pannello di diagnostica CORS

Il server simula la richiesta preflight e la richiesta effettiva per determinare rapidamente se il problema è in Allow-Origin, Allow-Headers o credentials.

Simula lato server le richieste preflight CORS e le richieste reali, verifica uno per uno i 6 header di risposta, localizza con precisione errori di configurazione cross-origin e fornisce codice di correzione per più framework come Nginx/Node.js/Spring.

Raccomandazioni correlate

Casi d'uso

  • Quando nella console del browser appare l'errore No 'Access-Control-Allow-Origin' header, usa immediatamente questo strumento per verificare gli header CORS effettivamente restituiti dall'API target
  • Durante la fase di integrazione frontend-backend in progetti separati, verifica che la configurazione CORS del backend funzioni correttamente, evitando di perdere tempo modificando la configurazione alla cieca
  • Dopo aver configurato un proxy inverso Nginx, Apache o un API Gateway (Kong/APISIX/Spring Cloud Gateway), verifica che le regole CORS siano trasmesse correttamente
  • Quando le richieste cross-origin con Cookie falliscono, commuta la modalità credentials per rilevare conflitti di configurazione tra Allow-Credentials e Allow-Origin
  • Dopo aver aggiunto header personalizzati (come X-Token, X-Requested-With) la richiesta viene bloccata, verifica se sono dichiarati correttamente in Allow-Headers
  • Richieste con metodi non semplici come PUT/DELETE/PATCH falliscono in CORS, verifica se Allow-Methods include il metodo corrispondente
  • Il frontend non riesce a leggere header di risposta personalizzati (come X-Request-Id, X-Total-Count), verifica la configurazione di Access-Control-Expose-Headers
  • Dopo accelerazione con CDN, CORS funziona a intermittenza, verifica se Vary: Origin è configurato correttamente per evitare che il CDN metta in cache risposte errate
  • Errori CORS occasionali in produzione, riproduci lo scenario del problema e conserva il messaggio di risposta completo per il debug del backend
  • Imparando i principi di CORS, osserva la funzione di ogni header di risposta tramite richieste reali, approfondendo la comprensione del meccanismo cross-origin

Come utilizzare

  1. Nel campo URL di destinazione, inserisci l'indirizzo completo dell'API da verificare (supporta http/https, deve includere il percorso)
  2. Nel campo Origin della richiesta, inserisci l'origine effettiva della tua pagina frontend (come https://example.com, importante includere protocollo e porta, senza percorso)
  3. Seleziona il metodo HTTP (GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS), predefinito GET
  4. Nell'area degli header personalizzati, aggiungi gli header che devi inviare, uno per riga nel formato X-Token: abc123. Content-Type con tipi non semplici come application/json attiverà automaticamente preflight
  5. Seleziona l'opzione «Con credenziali (credentials)» in base al tuo scenario; se il tuo codice frontend usa withCredentials=true o credentials: 'include' in fetch, devi selezionarla
  6. Clicca sul pulsante «Avvia verifica», lo strumento invierà in sequenza dal server la richiesta preflight OPTIONS e la richiesta reale (se il preflight passa o non è necessario)
  7. Consulta il report di analisi: guarda prima il risultato di valutazione generale, poi verifica lo stato di ogni header CORS uno per uno, regola la configurazione del server secondo le raccomandazioni di correzione degli errori in rosso, riverifica dopo la correzione

Funzionalità

  • Simulazione reale lato server delle richieste preflight e reali, senza interferenze dalla cache del browser o dalle estensioni, risultati più precisi
  • Mostra separatamente la risposta preflight OPTIONS e la risposta reale GET/POST, distinguendo chiaramente in quale fase si verifica il problema
  • Verifica uno per uno i 6 header CORS principali: Access-Control-Allow-Origin, Allow-Methods, Allow-Headers, Allow-Credentials, Expose-Headers, Max-Age, ogni header contrassegnato individualmente con stato superamento/avviso/errore
  • Rileva intelligentemente il conflitto classico tra wildcard * e modalità credentials, allertando immediatamente su questa trappola di configurazione più comune
  • Supporta origine di richiesta Origin personalizzata, metodi HTTP (GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS) e header di richiesta personalizzati arbitrari
  • Permette di commutare la modalità con o senza credenziali (Cookie/header Authorization/certificati client TLS), simulando scenari con withCredentials=true
  • Rileva automaticamente se l'header Vary: Origin è configurato correttamente, evitando che CDN/proxy inverso mettano in cache risposte CORS errate
  • Mostra in modo strutturato la configurazione della cache preflight Max-Age, valutando l'impatto della frequenza delle richieste preflight sulle prestazioni
  • Verifica la configurazione di Access-Control-Expose-Headers, confermando quali header di risposta possono essere letti da JavaScript lato frontend
  • Fornisce raccomandazioni di correzione riga per riga, inclusi esempi di configurazione per i principali framework server come Nginx, Apache, Node.js/Express, Spring Boot, Python/Django/Flask
  • Registra completamente i messaggi originali di richiesta e risposta, inclusi codice di stato, tutti gli header di risposta, anteprima del corpo della risposta, facilitando il debug approfondito
  • Identifica automaticamente le differenze tra richieste semplici e richieste che richiedono preflight, spiegando perché la tua richiesta attiva il preflight OPTIONS
  • Rileva problemi CORS negli scenari di reindirizzamento (se Origin cambia dopo reindirizzamenti 301/302/307/308)
  • Supporta il rilevamento di scenari di contenuto misto HTTPS/HTTP, allertando sui problemi correlati a CORS causati da contenuto misto

Domande frequenti

Perché con Postman/curl l'API funziona bene, ma quando accede il browser segnala errore cross-origin?

Questo è il problema CORS più classico! Perché Postman e curl non sono affatto soggetti alla politica della stessa origine del browser — sono client HTTP, non browser, non intercettano risposte, e non inviano neanche automaticamente richieste preflight OPTIONS. Gli errori cross-origin sono un meccanismo di sicurezza esclusivo del browser; solo l'ambiente di esecuzione JavaScript del browser effettua verifiche CORS. Che Postman possa connettersi dimostra solo che l'API stessa può restituire dati, non dimostra che la configurazione CORS sia corretta. Devi usare il browser, o questo strumento (che simula il flusso CORS del browser sul server) per verificare, e lì scoprirai il problema.

L'errore CORS è un problema del frontend o del backend? Chi deve correggerlo?

Il 99% degli errori CORS sono problemi di configurazione del backend (o problemi di configurazione nello strato Nginx/gateway), il frontend può fare ben poco. Il cuore di CORS è che il server «autorizza» il browser tramite header di risposta per permettere l'accesso cross-origin; il frontend può solo configurare withCredentials, impostare header di richiesta ecc., non può eludere le restrizioni di sicurezza del browser. I proxy del frontend di cui si parla su internet (proxy devServer, proxy inverso Nginx che proxano frontend e API sulla stessa origine) essenzialmente «ingannano» il browser facendogli credere che sia una richiesta stessa origine, non risolvono realmente il problema CORS; in produzione se frontend e backend sono origini diverse il backend deve comunque configurare CORS correttamente.

Perché la mia richiesta GET non ha cross-origin, ma non appena la cambio in POST/PUT appare cross-origin?

Perché GET normalmente soddisfa le condizioni di richiesta semplice, il browser invia la richiesta direttamente; mentre POST se invii Content-Type: application/json (il 90% delle API POST sono così), non appartiene più a richiesta semplice, attiverà preflight OPTIONS. La richiesta preflight richiede che il server restituisca gli header CORS corretti; molta gente ha configurato header CORS solo per GET/POST ma non ha gestito il metodo OPTIONS, o la risposta OPTIONS non ha header, quindi segnala errore. I metodi PUT/DELETE/PATCH di per sé non sono metodi semplici, attivano inevitabilmente preflight.

Come risolvere il cross-origin in ambiente di sviluppo? E in produzione?

In ambiente di sviluppo ci sono diverse soluzioni: ① Proxy integrato nel framework (devServer.proxy di Vue CLI, server.proxy di Vite, proxy di Create React App): proxano le richieste di API sulla stessa origine del server di sviluppo del frontend, il browser crede che sia richiesta stessa origine senza cross-origin; ② Disattivare parametri di sicurezza del browser (per esempio Chrome con parametro di avvio --disable-web-security), solo per test temporanei locali, assolutamente non per navigazione normale; ③ Configurare CORS sul backend autorizzando l'origine localhost (consigliato, comportamento coerente con la produzione). In produzione il backend deve configurare CORS correttamente: configurare whitelist di origini autorizzate, impostare correttamente Allow-Methods/Allow-Headers/Allow-Credentials, aggiungere Vary: Origin, o usare gateway/Nginx per gestire CORS in modo unificato.

Si può configurare Access-Control-Allow-Origin con più origini? Come configurare più domini per autorizzare il cross-origin?

No, l'header di risposta Access-Control-Allow-Origin può avere un solo valore, sia un'origine specifica (come https://a.com), sia *. Il browser non accetta più origini (per esempio scrivere https://a.com,https://b.com è invalido, il browser lo considererà non corrispondente). Il modo corretto di configurazione multi-origine è: il server mantiene una whitelist di origini autorizzate, ogni volta che riceve una richiesta legge il valore di Origin nell'header di richiesta, verifica se quell'Origin è nella whitelist, se sì imposta Access-Control-Allow-Origin come quel valore di Origin specifico, e restituisce contemporaneamente l'header Vary: Origin; se non c'è, non restituisce header CORS o restituisce errore. Non provare a restituire più header Allow-Origin o separare più valori con virgola, il browser non li riconosce.

La richiesta preflight OPTIONS ha bisogno di restituire logica di business? Può restituire direttamente 204?

La richiesta preflight OPTIONS non ha bisogno di restituire nessuna logica di business né corpo di risposta, ha solo bisogno di restituire gli header di risposta CORS corretti e codice di stato 200/204 è sufficiente. Il browser ricevendo gli header CORS corretti considera che il preflight è passato, non leggerà il contenuto del body della risposta OPTIONS. Quindi la migliore pratica è: intercettare direttamente le richieste OPTIONS nello strato Nginx/gateway, restituire 204 No Content e gli header CORS corretti, senza inoltrare al server applicativo backend; questo alleggerisce il carico del backend ed evita anche errori 405 causati da route backend che non supportano OPTIONS. Ma assicurati che gli header CORS della risposta OPTIONS siano coerenti con gli header CORS della richiesta reale.

Perché ho configurato withCredentials: true, ma Cookie non viene portato?

Le richieste cross-origin con Cookie richiedono di soddisfare contemporaneamente tre condizioni: ① XMLHttpRequest.withCredentials = true nel frontend o credentials: 'include' in fetch; ② Header di risposta backend Access-Control-Allow-Credentials: true; ③ Access-Control-Allow-Origin non può essere *, deve essere origine specifica. Le tre condizioni sono indispensabili. Inoltre fai attenzione agli attributi dei Cookie: il Cookie deve avere impostato SameSite=None; Secure (ambiente HTTPS) per poter essere portato in richieste cross-origin; se il Cookie è SameSite=Lax o Strict, in richieste cross-origin non verrà portato; l'attributo Domain del Cookie deve essere configurato correttamente; fai anche attenzione all'impatto delle politiche sui Cookie di terze parti (browser come Chrome hanno restrizioni sui Cookie di terze parti).

Che relazione c'è tra CORS e CSRF? Configurare CORS causerà vulnerabilità CSRF?

CORS è l'allentamento delle restrizioni di accesso cross-origin, CSRF è un attacco di falsificazione di richiesta tra siti, sono concetti diversi. Configurare CORS correttamente non causa direttamente vulnerabilità CSRF — perché CORS permette solo a JS di leggere risposte, mentre CSRF è quando un attaccante induce l'utente a inviare richieste a sua insaputa (come tag img, invio automatico di moduli), queste richieste anche senza CORS vengono inviate portando Cookie. Difendere dal CSRF richiede di usare CSRF Token, SameSite Cookie, verificare Origin/Referer e altre soluzioni, non si può difendere dal CSRF disabilitando CORS. Ma se durante la configurazione di CORS imposti Allow-Origin come * e autorizzi le credenziali, amplificherà effettivamente il rischio CSRF, ecco perché in scenari con credenziali non si può assolutamente usare *, devi restringere strettamente la whitelist di origini.

Il download di file, i reindirizzamenti, il caricamento di tag img/script hanno problemi CORS?

Il caricamento di risorse cross-origin con normali tag <img>, <script>, <link> (immagini CDN, script JS, CSS) di default non ha problemi CORS; queste sono «risorse incorporate» non «richieste AJAX», il browser permette di caricarle ma JS non può leggerne il contenuto. Ma se vuoi manipolare immagini cross-origin in Canvas, o caricare queste risorse con fetch/XHR e leggerne il contenuto, allora hai bisogno di CORS, e contemporaneamente devi aggiungere l'attributo crossorigin sul tag. Il download di file cross-origin (clic su tag a per scaricare) di default non richiede neanche CORS. I reindirizzamenti influenzano CORS: se la richiesta preflight OPTIONS restituisce un reindirizzamento 3xx, il browser la rifiuterà direttamente (Preflight redirect is not allowed); se il reindirizzamento della richiesta reale è tra origini diverse, ogni salto deve restituire correttamente gli header CORS.

Come configurare CORS correttamente in Nginx? Date un esempio di configurazione funzionante?

Punti chiave della configurazione consigliata in Nginx: ① Usare la direttiva map per corrispondere con whitelist di Origins, impostando dinamicamente la variabile $cors_origin; ② Le richieste OPTIONS restituiscono direttamente 204 senza inoltrare al backend; ③ add_header ricorda di aggiungere il parametro always per assicurarti che le risposte di errore portino anche l'header; ④ Aggiungere Vary: Origin; ⑤ Configurare correttamente Allow-Methods/Allow-Headers/Credentials. Puoi trovare configurazioni di esempio nelle raccomandazioni di correzione dei risultati di rilevazione di questo strumento; forniamo frammenti di configurazione verificati per i principali framework come Nginx, Apache, Node.js Express, Spring Boot, Python Flask/Django, Koa, Go Gin.

Dopo aver configurato CORS, come verificare se ha effetto?

Passaggi per verificare CORS: ① Prima usa la rilevazione online di questo strumento, inserisci URL, Origin, metodo, header, opzione credenziali, guarda se ogni verifica del preflight e della richiesta reale passa; ② Apri il pannello Network di DevTools del browser, marca Disable cache per disabilitare la cache (evitando interferenza di cache vecchia), attiva la richiesta cross-origin, verifica che gli header di risposta del preflight OPTIONS e della richiesta reale siano corretti; ③ In Console guarda se ci sono errori correlati a CORS; ④ Prova diversi scenari: richieste GET senza header personalizzati, richieste POST con application/json, metodi PUT/DELETE, con Cookie/senza Cookie, con header personalizzati; ⑤ Simula una richiesta OPTIONS con curl: curl -i -X OPTIONS -H "Origin: https://yoursource.com" https://api.example.com/endpoint, verifica che gli header di risposta siano corretti.

Perché la richiesta cross-origin segnala errore su Chrome ma funziona normalmente su Safari/Firefox? O viceversa?

Diversi browser hanno differenze nei dettagli di implementazione della specifica CORS: ① Safari ha restrizioni più severe su Max-Age della cache preflight (versioni vecchie solo 600 secondi), la politica dei Cookie (ITP anti-tracciamento intelligente) è anch'essa più severa, può causare problemi di Cookie cross-origin; ② Chrome ha verifiche più severe sui wildcard con credenziali, Allow-Headers/Allow-Methods non permettono neanche *, alcune versioni di Firefox possono essere più permissive; ③ Il vecchio IE (IE11) usa XDomainRequest invece di XMLHttpRequest standard, l'implementazione CORS ha molte trappole (per esempio non supporta header personalizzati, supporta solo GET/POST); ④ Diversi browser hanno differenze sottili nella gestione dell'header Vary, gestione dei reindirizzamenti, gestione degli header di sicurezza. La soluzione è configurare strettamente secondo la specifica CORS, non dipendere dal comportamento compatibile di un browser specifico.

Quanto è appropriato impostare Access-Control-Max-Age? Quali problemi ci sono se è impostato troppo lungo o troppo corto?

Si consiglia di impostare tra 3600 (1 ora) e 86400 (24 ore). Impostare troppo corto (come 60 secondi): la cache preflight scade velocemente, inviando frequentemente richieste OPTIONS, aumentando il tempo di richiesta e la pressione del server, l'impatto è notevole in ambienti di rete mobile debole. Impostare troppo lungo (come 31536000, cioè un anno): se aggiorni la configurazione CORS (per esempio aggiungendo metodi autorizzati, header), il vecchio risultato preflight in cache nel browser dell'utente può impiegare molto tempo a scadere, durante quel periodo appariranno problemi di configurazione che non ha effetto. Inoltre Chrome e Firefox troncheranno automaticamente i valori che superano 86400 secondi a 86400 secondi, per quanto tu lo imposti non serve. In ambiente di sviluppo puoi impostare -1 per disabilitare la cache preflight, facilitando il debug.

Le connessioni WebSocket hanno problemi cross-origin? CORS si applica a WebSocket?

WebSocket (ws:// e wss://) non sono soggetti al meccanismo CORS HTTP, perché WebSocket è un protocollo indipendente, non sono richieste HTTP AJAX. Ma la fase di handshake di WebSocket è una richiesta HTTP; il server può verificare l'header Origin per decidere se autorizzare la connessione — questo è un controllo di permessi a livello WebSocket, non è CORS standard, ma il principio è simile. Se la connessione WebSocket viene rifiutata, devi verificare la configurazione di verifica Origin del server WebSocket, non gli header CORS HTTP. Librerie come Socket.IO possono avere il proprio modo di configurare il cross-origin, simile alla configurazione CORS standard ma non esattamente uguale. Inoltre, altre API del browser come HTTP/2 Server Push, WebRTC hanno anch'esse il proprio controllo di permessi, non seguono completamente il CORS HTTP.

I risultati di rilevazione di questo strumento sono coerenti con il comportamento del browser? Perché con lo strumento la rilevazione passa ma il browser segnala ancora errore?

Questo strumento sul server simula strettamente secondo la specifica W3C CORS il flusso di preflight e richiesta reale del browser, la logica di verifica degli header CORS è fondamentalmente coerente con i browser moderni. Se lo strumento rileva che passa ma il browser segnala ancora errore, le possibili cause sono: ① Il browser ha messo in cache risultati preflight o risposte vecchie, fai ricaricamento forzato Ctrl+F5 o cancella la cache e riprova; ② Estensioni del browser (ad blocker, protezione privacy, plugin di sicurezza) hanno modificato o intercettato la richiesta; ③ L'Origin, gli header di richiesta, il metodo, l'opzione credenziali che hai scritto nello strumento non sono coerenti con quello che il frontend invia realmente (per esempio il frontend porta realmente un header personalizzato che non hai aggiunto nello strumento); ④ Cache incoerente sui nodi CDN/proxy, il nodo a cui lo strumento chiede e il nodo a cui il browser chiede restituiscono risultati diversi; ⑤ Il browser ha politiche di sicurezza speciali (come le richieste a contenuto misto HTTP in pagine HTTPS sono bloccate, restrizioni speciali del protocollo file:// di file locali).

Risoluzione dei problemi

La console del browser segnala errore No 'Access-Control-Allow-Origin' header, ma con curl/postman la richiesta può vedere gli header di risposta

Il server non ha configurato header CORS per il metodo OPTIONS: curl invia GET/POST può vedere gli header, ma il browser invia prima preflight OPTIONS, e la risposta OPTIONS non ha header Quando il server restituisce errori 4xx/5xx non porta header CORS: add_header di Nginx di default ha effetto solo per 2xx e alcuni 3xx, le risposte di errore necessitano di aggiungere il parametro always La richiesta è stata bloccata da WAF/firewall/plugin di sicurezza sul metodo OPTIONS, la risposta di blocco non ha header CORS Il CDN ha messo in cache una risposta vecchia senza header CORS (contaminazione di cache causata da mancanza di Vary: Origin) Estensioni del browser (come ad blocker, plugin di protezione della privacy) hanno modificato o intercettato gli header di richiesta cross-origin

Ho configurato Access-Control-Allow-Origin: *, ma le richieste con Cookie falliscono comunque

Questa è una restrizione obbligatoria della specifica CORS: finché la richiesta porta credenziali (withCredentials: true, Cookie, autenticazione HTTP), Allow-Origin non può assolutamente essere il wildcard * Anche se il frontend non ha impostato esplicitamente withCredentials, se il dominio target e il dominio attuale hanno Cookie, il browser può portarli automaticamente Non solo Allow-Origin non può essere *, Allow-Headers e Allow-Methods in alcuni browser con credenziali non possono neanche usare * Devi impostare contemporaneamente Access-Control-Allow-Credentials: true, e Allow-Origin restituisce l'origine della richiesta specifica invece di *

La richiesta preflight OPTIONS restituisce 405 Method Not Allowed o 404 Not Found

Le route del framework backend hanno configurato solo i metodi di business come GET/POST, non ci sono route che gestiscono il metodo OPTIONS Nella configurazione di Nginx la direttiva try_files ha intercettato la richiesta OPTIONS, restituendo direttamente 404 senza inoltrare al backend Configurazioni di API Gateway o gruppi di sicurezza hanno bloccato il metodo OPTIONS, considerandolo metodo «inutile» Framework come Spring Boot se il supporto CORS non è abilitato, rifiuteranno automaticamente le richieste OPTIONS restituendo 403 Nella progettazione di API RESTful non è stato configurato un handler indipendente per le richieste OPTIONS

Le richieste POST application/json segnalano sempre che l'header non è autorizzato, ma Content-Type è già aggiunto in Allow-Headers

Errore di battitura: maiuscole/minuscole o trattino scritti male in Content-Type (per esempio scrivere ContentType, Content-type, anche se la specifica non distingue maiuscole/minuscole alcuni server con corrispondenza stretta hanno problemi) L'header è stato aggiunto solo nelle risposte GET/POST, ma la risposta preflight OPTIONS non lo ha; il browser guarda gli header di OPTIONS Gli header elencati in Allow-Headers non sono completi: per esempio il frontend invia anche X-Requested-With o altri header personalizzati non elencati Valori con spazi in più: per esempio scrivere "Content-Type, Authorization" (spazio dopo virgola è accettabile, ma alcuni browser vecchi hanno problemi nell'analisi) Access-Control-Allow-Headers restituisce solo gli header richiesti nella richiesta preflight, invece di tutti gli header supportati (anche se la specifica lo permette, in alcuni scenari causa problemi)

La configurazione cross-origin funziona bene nei test locali, dopo il deploy su CDN/Nginx funziona a intermittenza con errori casuali

Manca l'header di risposta Vary: Origin! Il CDN mette in cache per URL, la prima richiesta con header CORS è in cache, le richieste successive di origini diverse ricevono risposta in cache errata Il CDN ha configurato regole di cache che mettono in cache anche la risposta preflight OPTIONS, dopo aver aggiornato la configurazione CORS sul backend il CDN ha ancora cache vecchia Nginx ha più livelli di add_header, gli header CORS dei livelli inferiori vengono sovrascritti dai livelli superiori o ci sono errori durante l'unione La funzione di ottimizzazione degli header HTTP del CDN cancella o sovrascrive automaticamente gli header Access-Control-* Contenuto misto HTTPS/HTTP: la pagina è HTTPS ma l'API è HTTP, il browser la blocca direttamente, sembrando un errore CORS Configurazione incoerente tra nodi CDN, alcuni nodi hanno header CORS e altri no

Il frontend può ottenere il codice di stato e i dati della risposta, ma non riesce a leggere header di risposta personalizzati (come X-Total-Count)

L'header di risposta Access-Control-Expose-Headers non è configurato! Di default la specifica CORS espone solo pochi header di risposta basilari per farli leggere a JS Gli header di risposta accessibili di default sono solo: Cache-Control, Content-Language, Content-Length, Content-Type, Expires, Last-Modified, Pragma Header di risposta personalizzati (X-Request-Id, X-Total-Count, Authorization, Set-Cookie ecc.) devono essere elencati in Expose-Headers Set-Cookie e Set-Cookie2 non saranno mai esposti a JS del frontend; è una restrizione di sicurezza del browser, non importa come lo configuri Anche se li elenchi in Expose-Headers, Set-Cookie non può essere letto tramite getResponseHeader, il browser lo filtrerà automaticamente

Glossario

CORS (Cross-Origin Resource Sharing)
Condivisione di Risorse tra Origini Diverse, standard W3C, che permette al server di dichiarare quali origini possono accedere alle risorse tramite nuovi campi di header HTTP, è la soluzione ufficiale dei browser moderni per risolvere problemi cross-origin.
Politica della Stessa Origine (Same-Origin Policy)
Meccanismo di sicurezza centrale del browser; solo quando protocollo, dominio e porta sono esattamente uguali si considera stessa origine, e JavaScript di origini diverse di default non può leggere le risorse dell'altro.
Richiesta Preflight (Preflight Request)
Richiesta con metodo OPTIONS che il browser invia automaticamente prima per richieste cross-origin non semplici, usata per chiedere al server se permette la richiesta reale successiva; solo dopo aver superato il preflight viene inviata la richiesta vera.
Richiesta Semplice (Simple Request)
Richiesta cross-origin che soddisfa condizioni specifiche (metodo GET/HEAD/POST, solo header sicuri, Content-Type specifico), che non ha bisogno di inviare preflight e invia direttamente la richiesta reale.
Access-Control-Allow-Origin (ACAO)
Header di risposta CORS principale, specifica l'origine autorizzata ad accedere alla risorsa, può essere un URI di origine specifico o wildcard *, con credenziali non si può usare *.
Access-Control-Allow-Methods (ACAM)
Header di risposta preflight, elenca tutti i metodi HTTP supportati dal server, più metodi separati da virgola.
Access-Control-Allow-Headers (ACAH)
Header di risposta preflight, elenca tutti i campi di header di richiesta autorizzati dal server; gli header personalizzati inviati dal frontend devono essere dichiarati qui.
Access-Control-Allow-Credentials (ACAC)
Header di risposta, valore booleano true indica che è permesso portare credenziali come Cookie e Authorization in richieste cross-origin; in questo caso Allow-Origin non può essere *.
Access-Control-Max-Age (ACMA)
Header di risposta preflight, specifica il tempo di cache del risultato preflight in secondi; una configurazione ragionevole può ridurre le richieste OPTIONS migliorando le prestazioni.
Vary: Origin
Header di risposta, dice a CDN/proxy che il contenuto della risposta varia in base all'header Origin della richiesta, nel caching deve includere Origin come chiave di cache per evitare disordine di cache delle risposte cross-origin.
Header di richiesta della lista sicura CORS (CORS-safelisted request headers)
Header di richiesta che possono essere inviati senza bisogno di dichiararli in Allow-Headers, inclusi Accept, Accept-Language, Content-Language, Content-Type (valori specifici) ecc.
Nomi di header proibiti (Forbidden header name)
Header di richiesta che il browser proibisce a JavaScript di impostare tramite programmazione, come Host, Connection, Cookie, Origin ecc.; questi header sono controllati automaticamente dal browser.
Richiesta con credenziali (Credentialed Request)
Richiesta cross-origin che porta credenziali di identità come Cookie, informazioni di autenticazione HTTP, certificati client TLS; richiede che frontend e backend configurino congiuntamente withCredentials e Allow-Credentials.
Access-Control-Expose-Headers
Header di risposta, elenca gli header di risposta a cui JavaScript può accedere; di default sono accessibili solo pochi header basilari, gli header personalizzati devono essere dichiarati qui.
Metodo OPTIONS
Uno dei metodi HTTP, usato per ottenere le opzioni di comunicazione supportate dal server; CORS lo usa per inviare richieste preflight, chiedendo al server i metodi, header, credenziali autorizzati.
Header di richiesta Origin
Header di richiesta aggiunto automaticamente dal browser, indica da quale origine proviene la richiesta attuale (protocollo+dominio+porta); il server determina se autorizzare il cross-origin in base a questo header.
Attributo crossorigin
Attributo di elementi HTML (come script, img, link), usato per specificare se si abilita il caricamento di risorse con CORS; i valori sono anonymous (senza credenziali) e use-credentials (con credenziali).
Modalità di richiesta no-cors
Una mode dell'API fetch, che permette di inviare richieste cross-origin ma può inviare solo richieste semplici e JavaScript non può leggere il contenuto della risposta, equivalente a inviare una richiesta opaca (Opaque Response).

Tabella di confronto completa degli header di risposta CORS

Header di rispostaFunzioneValore di esempioNote importanti
Access-Control-Allow-OriginSpecifica l'origine autorizzata per l'accesso cross-originhttps://example.com o *Con credenziali non si può assolutamente usare *, deve restituire Origin specifico; restituzione dinamica deve aggiungere Vary: Origin
Access-Control-Allow-MethodsElenca tutti i metodi HTTP supportati dal serverGET, POST, PUT, DELETE, PATCH, OPTIONSObbligatorio nella risposta preflight; bisogna elencare tutti i metodi, non solo il metodo della richiesta attuale
Access-Control-Allow-HeadersElenca tutti i campi di header di richiesta autorizzatiContent-Type, Authorization, X-TokenObbligatorio quando la richiesta preflight ha Access-Control-Request-Headers; gli header personalizzati devono essere inclusi; con credenziali alcuni browser non permettono *
Access-Control-Allow-CredentialsSe le credenziali (Cookie ecc.) sono autorizzatetruePuò essere solo la stringa "true" in minuscolo, non 1 né True; quando impostato su true Allow-Origin non può essere *
Access-Control-Expose-HeadersElenca gli header di risposta che JS può leggereX-Request-Id, X-Total-CountDi default si possono leggere solo Cache-Control/Content-Language/Content-Type/Expires/Last-Modified/Pragma; gli header personalizzati devono essere elencati qui
Access-Control-Max-AgeTempo di cache del risultato preflight (secondi)3600Limite Chrome/Firefox 86400 secondi (2 ore), Safari più corto; valore -1 disabilita la cache inviando preflight ogni volta
VaryIndica a CDN/proxy quali header di richiesta influenzano il contenuto della rispostaOriginQuando si restituisce Allow-Origin dinamico bisogna aggiungere Vary: Origin, altrimenti la cache CDN causerà problemi cross-origin intermittenti
Access-Control-Request-MethodHeader di richiesta preflight, indica al server quale metodo usa la richiesta realePUTInviato automaticamente dal browser nelle richieste OPTIONS, non richiede configurazione manuale nel frontend
Access-Control-Request-HeadersHeader di richiesta preflight, indica al server quali header porterà la richiesta realecontent-type, x-tokenInviato automaticamente dal browser nelle richieste OPTIONS, più header separati da virgola

Tabella di determinazione di quali richieste attivano preflight

Condizione di attivazioneAttiva preflight?Spiegazione dettagliata
Il metodo di richiesta è un metodo diverso da GET/HEAD/POST (PUT/DELETE/PATCH/CONNECT/OPTIONS/TRACE)Finché il metodo non è questi tre, anche senza header personalizzati attiverà definitivamente preflight
Content-Type non è text/plain, multipart/form-data, application/x-www-form-urlencodedIl più comune application/json attiva definitivamente preflight! Molta gente incappa in questa trappola
La richiesta contiene header personalizzati (non nella lista sicura CORS)Per esempio X-Token, X-Requested-With, Authorization, X-Custom-Header ecc. attivano tutti
ReadableStream è usato come corpo di richiesta (upload in stream)Le moderne API di upload in stream del browser attivano preflight
Viene registrato un listener di eventi su XMLHttpRequest.upload (ascoltare il progresso di upload)Finché usi xhr.upload.onprogress attiverà preflight
Il metodo di richiesta è GET/HEAD/POST, Content-Type è uno dei tre tipi semplici, senza header personalizzatiNoQuesto appartiene a richiesta semplice, viene inviata direttamente, non invia OPTIONS
fetch imposta mode: 'no-cors'Non invia preflight CORS ma la risposta è opacaIn questa modalità JS non può leggere la risposta, può inviare solo richieste semplici
fetch imposta credentials: 'include' ma le altre condizioni sono di richiesta sempliceNon necessariamentecredentials da solo non attiva direttamente preflight, solo se ci sono altre condizioni di attivazione simultanee; attenzione che con credenziali la verifica CORS è più severa
Lo stesso URL ha avuto già preflight prima ed è entro il tempo di cache Max-AgeNo (hit cache)Durante il tempo di cache non rifarà OPTIONS, a meno che si disabiliti la cache o la cache scada

Tabella di riferimento rapido degli errori CORS comuni e soluzioni

Messaggio di errore in consoleCausa radiceSoluzione
No 'Access-Control-Allow-Origin' header is presentLa risposta non ha affatto header CORS; il server non ha configurato CORS; gateway/proxy ha mangiato gli header; risposte di errore 500/404 non portano headerVerifica la configurazione CORS del server; verifica che add_header di Nginx abbia aggiunto always; assicurati che le richieste OPTIONS restituiscano 2xx con header CORS
Valore di Allow-Origin 'XXX' non corrisponde all'Origin fornitaL'origine configurata in Allow-Origin non corrisponde all'Origin della richiesta reale; errore di configurazione (barra in più/porta errata/mix http/https)Verifica che la whitelist di Origins includa l'origine della richiesta; assicurati che non ci sia barra finale; www e senza www sono origini diverse; restituisci l'Origin corretto dinamicamente
La risposta preflight non ha superato il controllo di accesso: lo stato HTTP non è okLa richiesta OPTIONS restituisce stato non 2xx come 404/405/500; le route del server non gestiscono il metodo OPTIONS; try_files di Nginx ha intercettato OPTIONSAssicurati che le richieste OPTIONS restituiscano 200/204; configura la risposta OPTIONS su server/gateway; verifica che la configurazione Nginx gestisca OPTIONS correttamente
Il metodo XXX non è autorizzato da Access-Control-Allow-MethodsAllow-Methods nella risposta preflight non include il metodo HTTP che devi usare (come PUT non è elencato)In Access-Control-Allow-Methods elenca tutti i metodi che devi supportare, separati da virgola
Il campo di header XXX non è autorizzato da Access-Control-Allow-HeadersHai inviato un header personalizzato ma Allow-Headers non lo dichiara; il più comune è dimenticare Content-Type: application/json, AuthorizationIn Access-Control-Allow-Headers elenca tutti gli header di richiesta utilizzati, incluso Content-Type (quando è di tipo non semplice)
Quando il flag credentials è true, Allow-Origin non può essere il wildcard *Nelle richieste con credenziali (withCredentials=true) il server ha restituito Allow-Origin: *, questo è esplicitamente proibito dalla specificaNon si può usare *, deve restituire l'origine specifica in base all'Origin della richiesta; conferma anche Allow-Credentials: true
Quando il flag credentials è true, Allow-Headers non può essere il wildcard *Nelle richieste con credenziali Allow-Headers è stato impostato come *, alcuni browser (come Chrome) non lo permettonoElenca tutti gli header di richiesta effettivamente utilizzati, non usare *
Reindirizzamento preflight rifiutato (Preflight redirect is not allowed)La richiesta OPTIONS ha restituito un reindirizzamento 3xx, il browser non segue i reindirizzamenti delle richieste preflightAssicurati che la richiesta OPTIONS restituisca direttamente 200, non reindirizzi; correggi la configurazione del server per evitare salti su OPTIONS