Vai al contenuto principale

Daniele Irsuti
frontend developer

CORS: sicuro di conoscerlo?

CORS: è colpa del frontend o del backend? Cerchiamo di capire come funziona

CORS significa cross-origin HTTP request ed non è altro che una chiamata http effettuata attraverso browser da dominio-di-provenienza (es: www.dominio-di-provenienza.it) a dominio-di-destinazione (es: www.dominio-di-destinazione.it).

Un problema su cui tutti ci siamo schiantati almeno una volta è probabilmente questo:

Access to XMLHttpRequest at 'www.dominio-di-destinazione.it' from origin 'www.dominio-di-provenienza.it' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

Il motivo per cui incappiamo nel suddetto problema è che il server di dominio-di-destinazione non ha abilitato l’accesso al dominio-di-provenienza.

La cosa che spesso manda in confusione sviluppatore backend e sviluppatore frontend sta nel mezzo: il browser.

Perché?

Il browser per ragioni di sicurezza limita le richieste CORS e si accerta che sito di destinazione sia al corrente che la richiesta del sito di provenienza sia consentita.

Fatta questa premessa (ampiamente documentata su MDN) vorrei mostrare un esempio molto semplice di chiamata CORS che non va a buon fine.

Per rendere l’esempio di brutale immediatezza, mostrerò direttamente in console (sul dominio di questo blog) il codice per effettuare una chiamata Ajax costruita con Postman verso la pagina mdn che spiega proprio cos’è CORS.

Cors

La parte migliore che sfugge a... un sacco di gente

Quando si effettua una richiesta CORS, come nel caso mostrato nella gif di prima, parte una chiamata con metodo OPTIONS. Questa chiamata viene detta CORS preflight.

Di seguito il flusso di una CORS request con preflight.

Cors preflight

Quello che non molti sanno è che se la richiesta soddisfa determinati requisiti la CORS preflight non è necessario che venga effettuata:

Simple request

Metodi permessi:

  • GET

  • HEAD

  • POST

Header permessi:

  • Accept

  • Accept-Language

  • Content-Language

  • Content-Type con uno dei seguenti valori:

    • application/x-www-form-urlencoded

    • multipart/form-data

    • text/plain

  • DPR

  • Downlink

  • Save-Data

  • Viewport-Width

  • Width

Sarà vero? Provo!

Esempio di simple request

Quando vado a visualizzare l’header non è presente alcun preflight. C’è la POST request passa diretta. Nessun metodo OPTIONS.

Access-Control-Allow-Origin

Come abbiamo scritto in precedenza, la richiesta partita è consentita solo se dominio-di-provenienza la consente, altrimenti restituirà errore.

Per essere consentita, il browser verifica che nell’header di risposta sia presente la chiave ”Access-Control-Allow-Origin” con valore “dominio-di-provenienza” o, come spesso avrete visto, ”*” (ossia da qualsiasi provenienza).

Quindi lato backend che faccio?

Non è raro trovare soluzioni raffazzonate come applicare negli header del dominio-di-destinazione:

Access-Control-Allow-Origin: *

Fino a quando si tratta di simple request può andare bene, ma come come comportarsi quando ad arrivare sono richieste con metodo OPTIONS?

L’ideale sarebbe intercettare tutte le richieste OPTIONS e ritornare una risposta contenente i seguenti header:

HTTP STATUS 200
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS,
Access-Control-Allow-Headers: Content-Type

Ma è un soluzione artigianale, generalmente i framework più popolari hanno delle configurazioni già built-in che facilitano lo sviluppatore nel compito, possibilmente scrivendo anche una sola riga di codice.

Considerazioni personali

Io credo che tutti, veramente tutti, debbano conoscere CORS, frontender e backender. Per questo vi suggerisco vivamente di leggere l’articolo presente su MDN molto più tecnico ed accurato.

Fonti e approfondimenti

Daniele Irsuti

Scritto da Daniele Irsuti

Specializzato in applicazioni React, React Native e vanilla. È un appassionato di grafica, psicologia e scrittura

Contattami

Mi vuoi contattare per qualcosa in particolare? Scrivi nel form sottostante, proverò a risponderti nel minor tempo possibile