Partage des ressources entre origines multiples (CORS)

Partager des ressources entre origines de manière sécurisée

Mariko Kosaka

Le règlement d'origine identique du navigateur bloque la lecture d'une ressource à partir d'une autre origine. Ce mécanisme empêche les sites malveillants de lire les données d'autres sites, mais il empêche également les utilisations légitimes.

Les applications Web modernes souhaitent souvent obtenir des ressources à partir d'une autre origine, par exemple en récupérant des données JSON à partir d'un autre domaine ou en chargeant des images d'un autre site dans un élément <canvas>. Il peut s'agir de ressources publiques qui devraient être accessibles à tous, mais la règle same-origin bloque leur utilisation. Les développeurs ont traditionnellement utilisé des solutions de contournement telles que JSONP.

Le partage de ressources entre origines multiples (CORS) résout ce problème de manière standardisée. L'activation de CORS permet au serveur d'indiquer au navigateur qu'il peut utiliser une origine supplémentaire.

Comment fonctionne une requête de ressources sur le Web ?

requête et réponse
Illustration de la requête client et de la réponse du serveur.

Un navigateur et un serveur peuvent échanger des données sur le réseau à l'aide du protocole HTTP (Hypertext Transfer Protocol). HTTP définit les règles de communication entre le demandeur et le répondeur, y compris les informations nécessaires pour obtenir une ressource.

L'en-tête HTTP négocie l'échange de messages entre le client et le serveur, et permet de déterminer l'accès. La requête du navigateur et le message de réponse du serveur sont tous deux divisés en en-tête et corps.

Informations sur le message, telles que le type de message ou l'encodage du message. Un en-tête peut inclure une variété d'informations exprimées sous forme de paires clé-valeur. L'en-tête de requête et l'en-tête de réponse contiennent des informations différentes.

Exemple d'en-tête de requête

Accept: text/html
Cookie: Version=1

Cet en-tête équivaut à dire "Je souhaite recevoir du code HTML en réponse. Voici un cookie que j'ai."

Exemple d'en-tête de réponse

Content-Encoding: gzip
Cache-Control: no-store

Cet en-tête équivaut à dire "Les données de cette réponse sont encodées avec gzip. Ne pas mettre en cache."

Corps

Le message lui-même. Il peut s'agir de texte brut, d'un binaire d'image, de JSON, de HTML ou de nombreux autres formats.

Comment fonctionne le CORS ?

Les règles de même origine indiquent au navigateur de bloquer les requêtes d'origines multiples. Lorsque vous avez besoin d'une ressource publique provenant d'une autre origine, le serveur fournissant la ressource indique au navigateur que l'origine qui envoie la requête peut accéder à sa ressource. Le navigateur s'en souvient et autorise le partage de ressources entre origines pour cette ressource.

Étape 1: Demande du client (navigateur)

Lorsque le navigateur envoie une requête d'origine croisée, il ajoute un en-tête Origin avec l'origine actuelle (schéma, hôte et port).

Étape 2: Réponse du serveur

Lorsqu'un serveur voit cet en-tête et souhaite autoriser l'accès, il ajoute un en-tête Access-Control-Allow-Origin à la réponse spécifiant l'origine de la requête (ou * pour autoriser n'importe quelle origine).

Étape 3: Le navigateur reçoit la réponse

Lorsque le navigateur voit cette réponse avec un en-tête Access-Control-Allow-Origin approprié, il partage les données de réponse avec le site client.

Partager des identifiants avec CORS

Pour des raisons de confidentialité, le CORS est généralement utilisé pour les requêtes anonymes, dans lesquelles l'auteur de la requête n'est pas identifié. Si vous souhaitez envoyer des cookies lorsque vous utilisez CORS, qui peuvent identifier l'expéditeur, vous devez ajouter des en-têtes supplémentaires à la requête et à la réponse.

Requête

Ajoutez credentials: 'include' aux options de récupération, comme dans l'exemple suivant. Cela inclut le cookie avec la requête comme suit:

fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})

Réponse

Access-Control-Allow-Origin doit être défini sur une origine spécifique (sans caractère générique à l'aide de *) et Access-Control-Allow-Credentials doit être défini sur true.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

Requêtes préliminaires pour les appels HTTP complexes

Lorsqu'une application Web envoie une requête HTTP complexe, le navigateur ajoute une requête préliminaire au début de la chaîne de requêtes.

La spécification CORS définit une requête complexe comme suit:

  • Requête qui utilise des méthodes autres que GET, POST ou HEAD.
  • Requête incluant des en-têtes autres que Accept, Accept-Language ou Content-Language.
  • Requête dont l'en-tête Content-Type est différent de application/x-www-form-urlencoded, multipart/form-data ou text/plain.

Les navigateurs créent automatiquement toutes les requêtes de prévol nécessaires et les envoient avant le message de requête réel. La requête de prévol est une requête OPTIONS, comme dans l'exemple suivant:

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

Côté serveur, l'application qui reçoit la requête répond à la requête de prévol avec des informations sur les méthodes que l'application accepte depuis cette origine:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

La réponse du serveur peut également inclure un en-tête Access-Control-Max-Age pour spécifier la durée (en secondes) pendant laquelle les résultats de prévol doivent être mis en cache. Cela permet au client d'envoyer plusieurs requêtes complexes sans avoir à répéter la requête préliminaire.