Partage des ressources entre origines multiples (CORS)

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

Mariko Kosaka

La règle d'origine commune du navigateur bloque la lecture d'une ressource provenant d'une origine différente. 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 d'origines différentes, par exemple pour récupérer des données JSON à partir d'un autre domaine ou charger des images à partir d'un autre site dans un élément <canvas>. Il peut s'agir de ressources publiques accessibles à tous, mais la règle de même origine bloque leur utilisation. Les développeurs ont toujours utilisé des solutions de contournement telles que le JSONP.

Le partage des 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 une demande de ressource fonctionne-t-elle sur le Web ?

requête et réponse
Illustration d'une requête client et d'une réponse du serveur.

Un navigateur et un serveur peuvent échanger des données sur le réseau à l'aide du protocole de transfert hypertexte (HTTP). Le protocole HTTP définit les règles de communication entre le demandeur et le répondant, 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 est utilisé pour déterminer l'accès. La requête du navigateur et le message de réponse du serveur sont divisés en un en-tête et un corps.

Informations sur le message, telles que son type ou son encodage. Un en-tête peut inclure différentes 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 biscuit que j'ai. »

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

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

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

Corps

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

Comment fonctionne CORS ?

La règle d'origine commune indique au navigateur de bloquer les requêtes multi-origines. Lorsque vous avez besoin d'une ressource publique d'une origine différente, le serveur qui fournit les ressources indique au navigateur que l'origine qui envoie la requête peut accéder à sa ressource. Le navigateur le mémorise et autorise le partage multi-origine des ressources pour cette ressource.

Étape 1: requête client (navigateur)

Lorsque le navigateur effectue une requête multi-origine, 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 à la réponse un en-tête Access-Control-Allow-Origin 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é, CORS est normalement utilisé pour les requêtes anonymes, dans lesquelles le demandeur n'est pas identifié. Si vous souhaitez envoyer des cookies lorsque vous utilisez CORS, qui peut 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 (aucun caractère générique utilisant *) 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 qui inclut des en-têtes autres que Accept, Accept-Language ou Content-Language.
  • Une requête ayant un en-tête Content-Type autre que application/x-www-form-urlencoded, multipart/form-data ou text/plain

Les navigateurs créent automatiquement toutes les requêtes préliminaires nécessaires et les envoient avant le message de requête réel. La requête préliminaire 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 préliminaire avec des informations sur les méthodes acceptées par l'application à partir de 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 de mise en cache des résultats préliminaires. Cela permet au client d'envoyer plusieurs requêtes complexes sans avoir à répéter la requête préliminaire.