
Introduction
Si vous traînez vos guêtres depuis quelques temps dans le développement logiciel, vous avez probablement déjà rencontré un message similaire à celui-ci dans la console de votre navigateur :
Access to fetch https://api.fr from origin https://frontend.fr has been blocked by CORS policy: <Some obscure reason>
Dans bon nombre de cas, une extension navigateur ou quelques lignes savamment copiées/collées côté serveur pourront faire disparaître ce désagrément sans trop avoir à comprendre les mécanismes derrière ce message d’erreur.
Mais dans certaines situations que nous allons explorer ensemble, pas d’autre choix que de se relever les manches du cerveau, et de plonger dans le monde fascinant du “partage des ressources entre origines multiples”, ou “Cross Origin Resource Sharing” en anglais, et qu’on abrège quasi systématiquement en “CORS”.
Les fondamentaux
"Same Origin Policy" et sécurité du navigateur
Pour commencer, le Cross Origin Resource Sharing est une extension d’un mécanisme de sécurité qui existe dans le navigateur depuis Netscape 2.02 en 1995 : la “Same Origin Policy”.
Si le navigateur n’implémentait pas cette mesure de sécurité, il serait possible pour un site web malveillant de réaliser des appels à votre insu vers un autre site pour aller lire les données d’un autre site et de les utiliser à des fins malicieuses. Cette attaque est typiquement utilisée par des sites qui servent de leurre (spoofing) :

La Same Origin Policy est donc un rempart pour éviter ces scénarios d’attaque, qui sont à distinguer du Cross Site Request Forgery.
Pas de navigateur, pas de problème
C’est sans aucun doute le point le plus important et le moins bien compris :
Les erreurs concernant le “Cross Origin Resource Sharing” sont générées par le NAVIGATEUR qui essaye de vous protéger. Ce n’est pas à proprement parler le serveur qui “rejette” la requête.
On insistera à plusieurs reprises sur ce point, mais cela permet déjà d’expliquer pourquoi lorsque vous appelez une API depuis un autre serveur vous ne rencontrez pas de message de CORS.
Il en va de même pour d’autres clients HTTP comme Postman/Insomnia/Soap UI, à l’inverse du navigateur ils ne cherchent pas à vous protéger :

C’est quoi une “Origine”
Une origine, c’est la combinaison d’un protocole, d’un domaine et d’un port.
Si votre site HTML/JS est hébergé sur le domaine “https://mon-domaine.fr", le navigateur va autoriser les scripts JavaScript à effectuer des requêtes sans faire rentrer en jeu le mécanisme de CORS dans ces deux scénarios :
Appel vers | Résultat depuis https://mon-domaine.fr |
https://mon-domaine.fr/api | OK - le path ne rentre pas en considération dans l’origine |
https://mon-domaine.fr:443/ | OK - le port est le même ici, comme le port 443 est le port par défaut pour le protocole HTTPS |
En revanche, si votre site est hébergé à l’adresse “https://www.mon-domaine.fr:4321", tous ces exemples d’appels seront empêchés par la Same Origin Policy :
Appel vers | Résultat depuis https://mon-domaine.fr |
https://api.mon-domaine.fr:4321 | KO - le domaine n’est pas le même |
https://api.www.mon-domaine.fr:4321 | KO - bien qu’il s’agisse d’un sous-domaine, l’origine n’est pas considérée comme étant la même |
https://www.mon-domaine.fr:5500 | KO - le port est différent |
wss://www.mon-domaine.fr:4321 | KO - le protocole est différent (WebSocket versus HTTP) |
http://www.mon-domaine.fr:4321 | KO - le protocole est différent (http ici alors que le frontend est sur httpS) |
https://10.45.23.12:4321 | KO - même si la résolution DNS de “www.mon-domaine.fr" aboutissait à cette même adresse IP, cet appel serait malgré tout considéré comme un appel “Cross Origin”. |
En résumé, pour qu’un appel HTTP soit considéré comme étant sur la même origine, il faut donc que la combinaison suivante soit identique à celle du frontend :
- <protocol>:<domain>:<port> ou alors
- <protocol>:<ip>:<port>
Les limites de la Same Origin Policy
On voit que la sécurité par défaut du navigateur, qui nécessite que l’API et le frontend soient sur la même origine, amène des restrictions qui sont peu compatibles avec les architectures modernes.
Vous allez me demander : “Mais sur mon site à moi, je dois bien pouvoir forcer le navigateur à ignorer la same origin policy côté frontend ???”
La réponse est NON.

Héééééé oui, si vous êtes dans le scénario où vous appelez une API qui ne vous appartient pas et que cette API n’autorise pas l’origine depuis laquelle vous l’appelez, il n’y a tout simplement rien que vous puissiez faire côté frontend pour contourner cette restriction.
Nous l’avons vu dans notre premier exemple, cela mènerait à la possibilité pour un script malicieux (qui se cacherait par exemple dans une librairie que vous utilisez en dépendance…) de récupérer des données depuis un autre site.
Le Cross Origin Resource Sharing à la rescousse.
Considérez le CORS comme un mécanisme pour assouplir la same origin policy. C’est l’occasion de réinsister : le CORS prend sa place entre un NAVIGATEUR et un serveur. Tous les mécanismes qui consistent à restreindre une communication de serveur à serveur CE N’EST PAS DU CORS.
💡 La meilleure façon d’envisager le CORS d’un point de vue serveur, c’est de se poser la question “Sur quel(s) site(s) web est-ce que j’autorise du code JavaScript à accéder aux données que j’expose ?”
La spécification du CORS a vu le jour entre 2004 et 2006, et est devenue une recommandation officielle du W3C en 2014. Le standard introduit un ensemble d’en-têtes HTTP qui permettent au SERVEUR “d’accepter” une requête qui vient d’un navigateur depuis une origine différente.
Et c’est toute la difficulté du CORS : la problématique côté FRONTEND de vouloir appeler une API qui n’est pas sur le même domaine doit être résolue côté SERVEUR. Ceux qui ont le problème et ceux qui peuvent le résoudre sont parfois des personnes différentes avec des priorités différentes, des responsables différents, des compétences différentes…
Conclusion et Récapitulatif
Afin de rendre le sujet digeste, nous allons publier d’autres articles, dans lesquels nous allons explorer des scénarios qui nécessitent la configuration du CORS :
- Vous souhaitez envoyer des en-têtes de requête HTTP customs
- Vous devez consommer une API REST avec des endpoints de type PUT, PATCH ou DELETE
- Vous souhaitez ajouter automatiquement des cookies à vos appels
- Vous avez besoin de lire les en-têtes de réponse depuis le JavaScript
Avant de détailler comment est-ce qu’on configure le Cross Origin Resource Sharing, voici un récapitulatif des principaux points qu’on a vu :
- Les navigateurs appliquent par défaut une politique de sécurité appelée “Same Origin Policy”, qui restreint les appels HTTP effectués depuis le frontend uniquement vers la même “origine”.
- La Same Origin Policy est un rempart efficace pour des scénarios d’attaque où un script malicieux cherche à récupérer des données depuis un autre site à l’insu de l’utilisateur.
- L’origine est déterminée à partir du protocole (http://, https://, wss://), du domaine (my-domain.com) ET du port (:8080, :443).
- Si à la place du domaine on utilise l’adresse IP, il faut garder à l’esprit que “localhost” et “127.0.0.1” seront considérés comme deux domaines différents. Il faudra donc les configurer explicitement tous les deux si on souhaite utiliser les adresses IP.
- Le Cross Origin Resource Sharing est un mécanisme qui permet d’assouplir la Same Origin Policy
- Le CORS est mis en œuvre par le navigateur
- Il n’y a pas de notion de CORS pour une communication serveur à serveur
- La configuration du CORS se fait côté SERVEUR, bien que les “problèmes de CORS” s’observent côté navigateur. C’est principalement ce point qui rend les problèmes de CORS difficiles à résoudre et à investiguer.
- Côté serveur, la meilleure façon d’envisager le CORS est de se poser la question “Sur quel(s) site(s) Web est-ce que je souhaite autoriser du code JavaScript à accéder aux données que j’expose ?”.
A très bientôt pour la suite de cette série !
Références
https://developer.mozilla.org/fr/docs/Web/Security/Same-origin_policy
https://fetch.spec.whatwg.org/#http-cors-protocol