Gestire CORS nelle applicazioni Web

0
36
Shutterstock/Gorodenkoff

CORS è un meccanismo del browser che consente ai server di specificare le origini di terze parti che possono richiedere risorse da loro. È una protezione di sicurezza che aiuta a impedire ai siti dannosi di rubare dati di proprietà di altre origini.

CORS sta per Cross-Origin Resource Sharing. Quando si utilizza CORS per caricare una risorsa, il browser di solito invia un “preflight” Richiesta OPZIONI HTTP. Il server deve rispondere specificando le origini con cui interagirà. Può anche definire vincoli aggiuntivi, come le intestazioni HTTP che possono essere inviate.

Il browser controlla l'origine corrente e la richiesta in uscita rispetto alle specifiche del server. La richiesta può continuare se tutti i controlli passano. In caso contrario, la richiesta originaria verrà annullata. Quando ciò accade, viene visualizzato un avviso nella console.

Quando viene utilizzato CORS

I browser applicano CORS per le richieste Ajax e Fetch. Il meccanismo verrà utilizzato anche per font web, texture WebGL e disegni di immagini su tela con drawImage(). Qualsiasi richiesta idonea a un'origine di terze parti richiederà uno scambio CORS.

CORS non verrà applicato se la richiesta viene considerata “semplice”. Una richiesta semplice deve essere GET, HEAD o POST con un tipo di contenuto text/plain, application/x-www-form-urlencoded o multipart/form-data. Le uniche intestazioni di richiesta semplice consentite sono Accept, Accept-Language, Content-Language e Content-Type.

Se la richiesta non soddisfa tutti i criteri di cui sopra, i browser moderni avvieranno uno scambio CORS. È importante riconoscere che CORS è una tecnologia basata su browser – non incontrerai mai CORS mentre fai richieste manualmente, come con curl nel tuo terminale.

Gli scambi CORS non inviano sempre una richiesta di preflight OPTIONS. Un preflight viene utilizzato quando la richiesta causerebbe “effetti collaterali” sul server. Questo è generalmente il caso di metodi di richiesta diversi da GET.

Immagina una richiesta POST a /api/users/create. Il server creerebbe sempre un nuovo utente ma il browser potrebbe rifiutare l'accesso alla risposta se la richiesta fosse soggetta a CORS. Inviando prima una richiesta OPTIONS, il server ha la possibilità di rifiutare esplicitamente la richiesta reale. Ciò garantisce che l'account utente non venga effettivamente creato.

Gestione lato client CORS

Sebbene CORS sia una tecnologia browser, non puoi influenzarla direttamente con il codice lato client. Ciò impedisce agli script dannosi di aggirare le protezioni CORS per caricare dati da domini di terze parti.

CORS è solitamente trasparente, quindi non ti rendi conto che è in funzione. Se uno scambio CORS fallisce, il tuo codice JavaScript visualizzerà un errore di rete generico. Non è possibile ottenere dettagli precisi su cosa è andato storto, poiché ciò costituirebbe un rischio per la sicurezza. I dettagli completi vengono registrati nella console.

L'unico modo per risolvere un errore CORS è assicurarsi che il server invii le intestazioni di risposta corrette. Diamo ora un'occhiata a come viene fatto.

Gestione lato server CORS

Dovresti prima assicurarti che il tuo server gestisca correttamente le richieste OPTIONS. Potrebbe essere necessario creare un nuovo percorso nel framework web. In genere devi accettare le richieste OPTIONS a ciascun endpoint che potrebbe ricevere una richiesta multiorigine da un browser. La risposta non deve avere un corpo ma deve includere intestazioni specifiche che informano il browser su come procedere.

Inizia aggiungendo l'intestazione Access-Control-Allow-Origin. Questo specifica l'origine di terze parti a cui è consentito comunicare con il tuo endpoint. È possibile specificare una sola origine; puoi gestire più origini impostando dinamicamente il valore dell'intestazione sull'origine da cui è stata inviata la richiesta. Puoi ottenere l'origine corrente dall'intestazione della richiesta Origin.

Access-Control-Allow-Origin accetta * come valore jolly speciale. Ciò consentirà le richieste CORS da tutte le origini. Fare attenzione quando si utilizza questo – essere specifici con le origini consentite ti dà un maggiore controllo e impedisce a script dannosi di richiedere dati dal tuo server.

Access-Control-Allow-Origin deve essere incluso nella risposta del tuo server alla richiesta reale, così come nella risposta OPTIONS. Una volta configurata questa singola intestazione, sarà consentito uno scambio di base con un client browser di terze parti.

Specifica di intestazioni cross-origin

Le richieste CORS di solito supportano solo il “semplice” intestazioni di richiesta sopra elencate. Se hai bisogno di utilizzare qualsiasi altra intestazione, come Autorizzazione o un'intestazione personalizzata, il tuo server dovrà consentirla esplicitamente nella risposta di verifica preliminare.

Imposta l'intestazione Access-Control-Allow-Headers. Il suo valore dovrebbe essere un elenco separato da virgole di nomi di intestazioni che verranno accettati con la richiesta reale.

Access-Control-Allow-Headers: Authorization, X-Custom-Header

Il browser ora consentirebbe di continuare una richiesta con le intestazioni Authorization o X-Custom-Header.

Quando il browser invia una richiesta di preflight CORS, invierà l'intestazione Access-Control-Request-Headers. Contiene l'elenco delle intestazioni che verranno inviate con la richiesta effettiva. Il codice del tuo server può utilizzare queste informazioni per determinare come rispondere alla richiesta di verifica preliminare.

Limitazione a metodi di richiesta specifici

Analogamente alla specifica delle intestazioni di richiesta, gli endpoint del server possono definire quali metodi HTTP devono essere consentiti tra le origini. Imposta l'intestazione Access-Control-Allow-Methods come un elenco separato da virgole di nomi di metodi.

Access-Control-Allow-Methods: GET, POST, DELETE

Il browser invia l'Access-Control-Request- Intestazione del metodo con preflight CORS. Ciò consente al tuo server di conoscere il metodo HTTP che verrà utilizzato per effettuare la richiesta finale.

Cookie e credenziali

Le richieste CORS normalmente non inviano cookie in quanto potrebbero contenere credenziali sensibili che identificano il mittente. Se devi includere cookie con una richiesta cross-origin, devi abilitarlo esplicitamente nel tuo codice lato client:

fetch(“https://localhost/demo”, { mode: “cors”, credenziali: “includere” });

Inoltre, il server deve impostare l'intestazione della risposta Access-Control-Allow-Credentials: true per segnalare il proprio consenso allo scambio di cookie con credenziali.

Quando si utilizza Access-Control-Allow-Credentials, non è possibile utilizzare il carattere jolly (*) con Access-Control-Allow-Origin. Il server deve invece specificare un'origine esplicita per salvaguardare la privacy dell'utente. Se viene inviato il carattere jolly, il browser fallirà la richiesta con un errore CORS.

Preflight Caching

I preflight di CORS OPTIONS aggiungono un sovraccarico a ogni richiesta effettuata. Anche se il ritardo dovrebbe essere appena percettibile con una buona connessione di rete, è comunque uno spreco quando chiami lo stesso endpoint più volte in rapida successione.

Puoi dire al browser di memorizzare nella cache risposte di verifica preliminare impostando l'intestazione Access-Control-Max-Age. Il valore dovrebbe essere il tempo in secondi per il quale il browser può memorizzare nella cache la risposta. Le richieste successive allo stesso endpoint entro il periodo specificato non invieranno un preflight CORS.

Conclusione

CORS può sembrare confuso la prima volta che lo incontri. È una tecnologia browser controllata dalle risposte del server. CORS è inevitabile e tuttavia anche incontrollabile, a meno che tu non abbia accesso al codice lato server con cui stai interagendo.

L'effettiva implementazione di CORS è abbastanza semplice. Assicurati che la tua API o CDN stia inviando le intestazioni di risposta corrette, in particolare Access-Control-Allow-Origin. Avrai quindi una comunicazione sicura tra le origini che ti aiuterà a proteggerti dai cattivi attori.