Faire le quiz link W3C close

HTTP CORS

#1 A quoi sert CORS ? open

CORS veut dire Cross Origin Ressource Sharing. En français, ça peut se traduire par "partage de ressource entre origines multiples". Le mot important ici, c'est origine. On va voir tout de suite ce que c'est que l'origine.

Lorsque le navigateur charge une page web, elle lui est servie par un serveur. Il la récupère en donnant notamment trois informations : le protocole / le nom de domaine / le port. Bien sûr, il ne donne pas que ça, mais ce sont ces trois informations qui constituent l'origine de la page web. Déjà, il faut préciser une chose, c'est que deux origines sont identiques si les trois informations sont identiques.

Ensuite, cette page web lorsqu'elle se charge sur le navigateur, elle va demander des ressources. Pour demander une ressource, c'est pareil, le navigateur utilise un protocole, un nom de domaine et un port. Deux situations peuvent se présenter :

  1. La ressource demandée a la même origine que la page web. On dit que l'on est dans le cas Same Origin. Ce n'est pas le cas qui nous intéresse.
  2. La ressource demandée n'a pas la même origine que la page web. On dit que l'on est dans le cas Cross Origin. On veut pouvoir utiliser des ressources qui ont une origine différente. Et dans ce cas, si c'est une requête XMLHttpRequest ou une requête fetch qui demande la ressource, eh bien, cette dernière, par défaut, ne sera pas servie. Il faudra faire appel au protocole CORS pour débloquer la situation.
Qu'est ce que l'origine ?
Qu'est ce que l'origine d'une requête ?

Ce que j'ai appelé le protocole CORS (ce n'est pas vraiment un protocole), en fait, c'est un ensemble d'en-têtes HTTP utilisées par les requêtes HTTP qui sont échangées entre le navigateur et le serveur. Ces en-têtes vont permettre d'autoriser l'accès à des ressources d'origine différente.

Donc, vous allez entendre parler de CORS, lorsque votre navigateur est bloqué sur l'accès à une ressource. Ca se produit par exemple lorsque vous travaillez en localhost avec un framework sur une machine de dev et que vous faites des requêtes fetch vers votre Api Rest qui elle, se trouve sur une machine de prod. Ca se produit aussi si vous partagez des ressources entre un domaine et un sous-domaine. C'est considéré comme des domaines différents.

#2 Un exemple avec un fetch. open

Je vais faire un exemple 😎. Je vais regarder ce qui se passe si je fais une requête fetch, depuis une page servie par localhost, par exemple, en utilisant le plugin Live Server depuis l'éditeur Visual Studio Code. Je vais faire cette requête fetch vers une page PHP qui se trouve sur le domaine https://www.devenir-webmaster.com.

A priori, je ne prends aucune précaution particulière.

  1. Le script que va lancer Live Server c'est le script ci-dessous. Si vous voulez faire la manip vous copier / coller le code ci-dessous dans VSCode.
  2. Le code PHP qui est installé sur le domaine www.devenir-webmaster.com est ci-dessous. Je me contente de renvoyer une en-tête Content-Type et de répondre au fetch par un echo. Ce code est à votre disposition si vous voulez faire le tuto.
  3. Ensuite, je lance mon script avec Live Server.
    • La page fetch-1.html est servie par un serveur local interne au plugin Live Server à l'adresse 127.0.0.1 sur le port 5500 et en utilisant le protocole HTTP.
    • La page fetch-1.html fait une requête pour charger la ressource serveur-1.php sur le domaine www.devenir-webmaster.com et sur le port 443 (port par défaut) et en utilisant le protocole HTTPS.
    Avec Chrome, vous allez obtenir le résultat ci-dessous. Vous constatez qu'il y a une erreur et que la requête a été bloquée. Un extrait du message d'erreur est "blocked by CORS policy".
    Requête Cross Origin (sans précaution)
    Par défaut échec d'une requête Cross Origin
  4. On peut noter que, si je lance le même script, mais que cette fois-ci, je charge ma page fetch-1.html directement depuis le serveur qui héberge www.devenir-webmaster.com. Eh bien, cette fois-ci, le serveur accepte ma requête et répond OK. Pourquoi ? Eh bien, parce que là, je me place dans un cas Same Origin.

    Tester le code
    Requête Same Origin
    Par défaut success d'une requête Same Origin

Si je résume :

  • Dans le premier cas, la page fetch-1.html est servie par http://127.0.0.1:5500 et la ressource se trouve sur https://www.devenir-webmaster.com. L'origine de la page et celle de la ressource ne sont pas les mêmes. On se trouve dans le cas Cross Origin et le serveur ne répond pas à la requête. C'est la configuration CORS qui bloque. Il va falloir que le navigateur envoie des en-têtes CORS et que le serveur réponde par d'autres en-têtes CORS pour déverrouiller la situation.
  • Dans le deuxième cas, la page fetch-1.html est servie par https://www.devenir-webmaster.com (port 443) et la ressource se trouve sur https://www.devenir-webmaster.com (port 443). L'origine de la page et de la ressource sont les mêmes. On se trouve dans le cas Same Origin et le serveur répond à la requête. Dans ce cas là, CORS ne sert à rien !!
Origine d'une page html
Origine d'une requête au sens de CORS

#3 Mettre en oeuvre CORS. open

Ci-dessous, je vais faire ce qu'il faut au niveau de CORS pour pouvoir accéder à la ressource et faire sauter le verrou qui nous bloque.

  1. Côté navigateur, au niveau du fetch, je vais demander du CORS, en mettant {mode : cors} comme deuxième paramètre de fetch. Je pense que le mode : cors est activé par défaut avec fetch, mais il vaut mieux le demander de manière explicite, au moins, on est sûr.
  2. Côté serveur, au niveau PHP, je vais ajouter l'en-tête Access-Control-Allow-Origin. Je vais mettre une étoile comme valeur ce qui autorise toutes les origines.
  3. Ensuite, je reprends Live Server pour lancer ce script. Donc, on est dans une configuration Cross Origin.
Exemple d'échange d'entête CORS

On constate que le serveur répond à la requête. CORS ici est mis en oeuvre correctement.

#4 Autre cas de figure. Le prefligth. open

Maintenant, j'enlève l'en-tête Access-Control-Allow-Origin côté serveur. Je regarde ce qui se passe si je fais une requête autre qu'un GET ou qu'un POST, par exemple, un DELETE. Le but, c'est de voir apparaître un autre message d'erreur, et c'est pour cette raison que je vous montre ça.

Je lance ce script avec Live Server et je constate que dans la réponse, c'est une preflight request qui est refusée. En fait, dans ce cas le protocole CORS fait une requête pour demander au serveur quelles sont les autorisations. Je vous cite simplement ce cas de figure pour que vous puissiez l'identifier. Je ne vais pas plus loin.

Pré-requête prefligth CORS
prefligth CORS visible sur le réseau