La maledizione del CORS

La maledizione del CORS

La Maledizione

Chiunque si professi web developer, nel corso della sua vita professionale, deve aver incontrato almeno una volta questo errore:

Access to XMLHttpRequest at 'https://api.marcomontorsi.it/data' from origin 'https://www.marcomontorsi.it'
has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

L’origine dell’errore parte proprio dal significato dell’acronimo di CORS, ovvero: Cross-Origin Resource Sharing.

Come sistema di protezione da attacchi come CSRF (Cross-Site Request Forgery), di default le chiamate da domini diversi da quello dell’applicazione vengono bloccate.

Questo sistema era comodo agli inizi degli applicativi web, quando spesso le applicazioni erano monolitiche. Ma al giorno d’oggi, è frequente avere almeno la logica frontend separata da quella del backend o dover fare delle chiamate ad API REST o SOAP verso servizi terzi.

Quindi la necessità di chiamate verso altri domini diversi da quelli dell’applicazione è cresciuta notevolmente. Per rispondere a questa necessità, si è introdotta la politica di CORS. Tramite opportuni Headers nella risposta, le chiamate da altri domini vengono autorizzate. Per capire meglio il funzionamento del CORS, bisogna capire la divisione tra richiesta preflight e richiesta principale.

Richiesta Preflight

Questa richiesta è gestita dal Browser e viene eseguita prima della richiesta principale tramite una richiesta HTTP con metodo OPTIONS. Essa verifica se è autorizzata a procedere con la richiesta da un dominio diverso.

Come parametri di verifica vengono inviati insieme alla richiesta degli header:

  • Access-Control-Request-Method: metodo HTTP che verrà utilizzato nella richiesta principale (es. POST).
  • Access-Control-Request-Headers: lista degli header che verranno utilizzati nella richiesta principale.

Il server, in caso positivo, risponde con i seguenti headers:

  • Access-Control-Allow-Methods: Lista dei metodi HTTP concessi.
  • Access-Control-Allow-Headers: Lista degli header concessi.
  • Access-Control-Max-Age: Numero di secondi che il browser può cachare la risposta per evitare di continuare ad inviare richieste preflight.

Richiesta Principale

In caso di Richiesta preflight positiva, la richiesta “principale” viene inviata al server specificando in un header l’origine della chiamata (es. origin: marcomontorsi.it).

La risposta del server sarà successivamente completata con un header Access-Control-Allow-Origin, il quale indica l’origine permessa per l’API. Il valore può essere scelto tra:

  • null: origine non concessa.
  • ’*’: qualsiasi origine concessa.
  • Singola origine come https://example.com.

Diagramma del Flusso

Diagramma del flusso

CORS in Laravel

In Laravel, la gestione del CORS è affidata al file in config/cors.php:

<?php

return [

    'paths' => ['api/*', 'sanctum/csrf-cookie'], // Percorsi specifici all'interno dell'applicazione a cui si applicheranno le regole CORS definite nella configurazione.

    'allowed_methods' => ['*'], // Metodi concessi, con l'asterisco qualsiasi metodo è concesso.

    'allowed_origins' => ['*'], // Domini abilitati, con l'asterisco qualsiasi dominio è concesso.

    'allowed_origins_patterns' => [], //Questa chiave consente di specificare un elenco di pattern regolari (regex) che definiscono gli origini consentiti per le richieste CORS

    'allowed_headers' => ['*'], // Headers concessi, con l'asterisco qualsiasi metodo è concesso.

    'exposed_headers' => [], // Questa chiave consente di specificare un elenco di headers personalizzati che possono essere esposte al client come parte della risposta. Questi headers personalizzati possono essere accessibili tramite JavaScript sul client se specificate qui.

    'max_age' => 0, //Numero di secondi che il browser può cachare la risposta per evitare di continuare ad inviare richieste preflight.

    'supports_credentials' => false, // il server consentirà o meno il passaggio di credenziali nelle richieste CORS
    //https://stackoverflow.com/questions/69481452/what-does-supports-credential-mean-in-the-laravel-cors-php-file
];