La notion d'origine est un concept fondamental dans le développement web, en particulier pour la sécurité et la gestion des ressources. Elle est essentielle pour comprendre comment les navigateurs appliquent des politiques de sécurité comme la politique de même origine (Same-Origin Policy) et donc comment ils doivent se comporter lorsqu'une requête HTTP demande un fichier qui n'est pas exactement au même "emplacement" que la page web qui émet cette requête.
HTTP étant le protocole à la base du web, il a évolué depuis ses premières versions pour se perfectionner et ajouter des notions de sécurité qui n'étaient pas établies dès ses débuts car nous n'avions pas à disposition des technologies et API aussi avancées qu'aujourd'hui pour construire des applications.
La notion de CORS (Cross-Origin Resource Sharing) entre alors en jeu, souvent pour développer à l'aide d'API qu'on interroge avec des requêtes en front et la méthode fetch()
ou l'antique AJAX (alias XMLHttpRequest). C'est d'ailleurs dans le standard Fetch du WhatWG que nous retrouvons ces extensions au protocole HTTP, supportées depuis au moins 2014 et remplaçant efficacement JSONP.
Dans le cas présent, ce n'est pas le serveur qui va autoriser ou bloquer l'accès à une ressource mais bien le navigateur, en fonction de l'origine et des éventuels en-têtes HTTP renvoyés par le serveur... principalement pour empêcher les attaques CSRF (Cross-Site Request Forgery) et à limiter l'accès aux ressources sensibles d'un site web par des scripts exécutés depuis une autre origine.
Sans CORS, un site malveillant pourrait charger une page de votre banque en arrière-plan et récupérer des données sensibles via une requête AJAX ou fetch, voire effectuer une requête malveillante (ex: déclencher un virement).
Qu'est-ce qu'une origine ?
Une origine (ou origin
en anglais) est définie par trois composants principaux :
- Protocole (Scheme) : Le protocole utilisé, surtout
http
ouhttps
puisqu'on fait du web. - Nom de domaine (Host ou Hostname) : Le nom de domaine du site web, par exemple
www.kiwipedia.fr
. - Port : Le numéro de port, par exemple
80
pour HTTP ou443
pour HTTPS.
Deux adresses ou plus précisément URLs (Uniform Resource Locator) ont la même origine si elles partagent ces 3 composants : le même protocole, le même nom de domaine et le même port.
Exemples
- ✅
http://www.kiwipedia.fr/page1.html
ethttp://www.kiwipedia.fr/page2.html
ont la même origine (facile !). - ⛔
http://www.kiwipedia.fr
ethttps://www.kiwipedia.fr
ont des origines différentes (différents protocoles). - ⛔
http://www.kiwipedia.fr
ethttp://kiwipedia.fr
ont des origines différentes (différents noms de domaine / sous-domaine). - ⛔
http://www.kiwipedia.fr
ethttp://www.kiwipedia.fr:8080
ont des origines différentes (différents ports).
Politique de même origine (Same-Origin Policy)
La politique de même origine est une mesure de sécurité importante, restreignant la manière dont les documents ou scripts d'une origine peuvent interagir avec les ressources d'une autre origine.
👉 Ce qui est permis par défaut :
- Une page peut librement interagir avec une autre page de la même origine.
- Les requêtes fetch ou AJAX peuvent être effectuées vers la même origine sans restriction.
👉 Ce qui est restreint :
- Les requêtes asynchrones (XHR, fetch) vers une origine différente sont bloquées par défaut (sauf si CORS est configuré).
- L'accès aux cookies, au stockage local et aux autres données sensibles est limité à la même origine.
CORS (Cross-Origin Resource Sharing)
Pour permettre des interactions entre différentes origines, les serveurs peuvent utiliser CORS qui est un mécanisme permettant à un serveur d'indiquer les origines autorisées à accéder à ses ressources. Cela se fait via des en-têtes HTTP spécifiques dont la plus connue est Access-Control-Allow-Origin
.
Preflight 🛫
Une requête Preflight est une mesure de sécurité qui protège les utilisateurs contre les attaques CSRF et assure que seules les requêtes autorisées puissent être exécutées. Elle est déclenchée si la requête :
- Utilise une méthode HTTP autre que
GET
,POST
ouHEAD
(commePUT
,DELETE
,PATCH
). - Contient des en-têtes personnalisés (
Authorization
,X-Custom-Header
, etc.). - Utilise un
Content-Type
autre queapplication/x-www-form-urlencoded
,multipart/form-data
, outext/plain
.
Le navigateur va donc envoyer une requête HTTP "CORS Preflight" avant une requête principale lorsqu'une requête vers une autre origine est effectuée. Elle a pour but de vérifier si la requête principale est autorisée.
1️⃣ Le navigateur envoie une requête HTTP OPTIONS
: elle ne contient aucune donnée sensible (cookies, tokens, etc.) et inclut plusieurs en-têtes spécifiques pour demander les permissions au serveur.
OPTIONS /api/ HTTP/1.1
Origin: https://www.alsacreations.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization
2️⃣ Le serveur répond poliment avec les en-têtes CORS :
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://www.alsacreations.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 3600
- Si le serveur accepte la requête, il renvoie une réponse avec les en-têtes CORS (
Access-Control-Allow-*
). - Si les règles CORS du serveur ne permettent pas la requête principale, le navigateur bloque la requête.
Pour autoriser toutes les origines, on peut utiliser le joker Access-Control-Allow-Origin: *
ce qui rend la ressource de facto "publique". Par contre il n'est pas possible d'indiquer une suite d'origines (de domaines) différents. Pour contourner cette limitation, on peut utiliser un langage back-end ou un proxy qui renverra la valeur appropriée en fonction de la provenance de la première requête.
Exemple de configuration pour Apache
Pour configurer CORS dans Apache, vous pouvez utiliser le module mod_headers
pour définir les en-têtes nécessaires ; il est la plupart du temps activé par défaut. Voici un exemple de configuration :
<VirtualHost *:80>
DocumentRoot /var/www/kiwipedia.fr
ServerName www.kiwipedia.fr
<Directory /var/www/kiwipedia.fr>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Configuration CORS
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://www.alsacreations.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type"
</IfModule>
</VirtualHost>
Ceci peut aussi être placé dans un fichier .htaccess
à la racine de votre projet.
- Access-Control-Allow-Origin : Spécifie l'origine autorisée à accéder aux ressources. Vous pouvez utiliser
*
pour autoriser toutes les origines, mais cela n'est pas recommandé pour des raisons de sécurité. - Access-Control-Allow-Methods : Méthodes HTTP autorisées pour les requêtes CORS.
- Access-Control-Allow-Headers : En-têtes HTTP autorisés dans les requêtes CORS.
Exemple de configuration pour Nginx
Dans Nginx, vous pouvez ajouter les en-têtes nécessaires dans votre bloc de configuration server
. Voici un exemple :
server {
listen 80;
server_name www.kiwipedia.fr;
root /var/www/kiwipedia.fr;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
# Configuration CORS
add_header 'Access-Control-Allow-Origin' 'https://www.alsacreations.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
}
Situations délicates et erreurs
Si l'origine (origin) n'est pas correctement configurée, vous pouvez rencontrer plusieurs types d'erreurs qui seront rapidement visibles dans la console du navigateur
...et qui peuvent être inspectées dans l'onglet "Réseau" (ou Network).
Elles seront principalement liées à la politique de même origine (Same-Origin Policy) et aux configurations CORS (Cross-Origin Resource Sharing). Voici quelques erreurs courantes et les cas où elles peuvent se produire :
Erreurs CORS
Access to XMLHttpRequest at 'URL' from origin 'ORIGIN' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Cette erreur (la plus courante) se produit lorsque le serveur ne renvoie pas l'en-tête Access-Control-Allow-Origin
nécessaire pour autoriser les requêtes provenant d'une origine différente. Cela peut se produire lors de requêtes XHR ou fetch. Dans ce cas il suffira d'ajouter correctement l'en-tête attendu pour débloquer la situation.
Access to XMLHttpRequest at 'URL' from origin 'ORIGIN' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
Cette erreur se produit lorsque vous essayez d'inclure des informations d'identification (comme des cookies ou des en-têtes d'autorisation) dans une requête CORS, mais que le serveur utilise *
comme valeur pour Access-Control-Allow-Origin
. Pour inclure des informations d'identification, le serveur doit spécifier explicitement l'origine autorisée.
Access to XMLHttpRequest at 'URL' from origin 'ORIGIN' has been blocked by CORS policy: Method 'METHOD' is not allowed.
Cette erreur se produit lorsque la méthode HTTP utilisée dans la requête (par exemple, POST
, PUT
) n'est pas autorisée par le serveur. Le serveur doit inclure cette méthode dans l'en-tête Access-Control-Allow-Methods
.
Erreurs liées à la politique de même origine
Blocked a frame with origin "ORIGIN" from accessing a cross-origin frame.
Cette erreur se produit lorsque du code JavaScript d'une page tente d'accéder au contenu d'une iframe provenant d'une origine différente. La politique de même origine empêche cet accès pour des raisons de sécurité (parce que les iframes c'est bien pratique, mais il y a des failles tout de même...)
Uncaught DOMException: Blocked a frame with origin "ORIGIN" from accessing a cross-origin frame.
Similaire à l'erreur précédente, cela peut se produire lors de tentatives d'accès à des objets DOM dans une iframe provenant d'une origine différente (on a déjà dit que les iframes c'est pratique, mais... ?)
Erreurs liées aux cookies et au stockage local
Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
Celle-ci est un peu plus "logique" : elle se produit si une page tente d'accéder à localStorage
depuis une origine différente, ce qui est interdit, également pour des raisons de sécurité. En général si on s'y prend bien, on ne devrait pas la rencontrer souvent.
Tester ?
Si vous devez contourner ces contraintes lorsque vous développez, soit pour tester la configuration avant/après, soit parce que vous n'avez pas encore eu l'occasion d'ajouter les bons en-têtes HTTP, sachez qu'il existe des extensions navigateur qui permettent d'ignorer ces politiques de sécurité par exemple CORS Everywhere sous Firefox. Évidemment il faudra penser à revenir à la situation normale ensuite ;)
Commenter
Vous devez être inscrit et identifié pour utiliser cette fonction.
Connectez-vous (déjà inscrit)
Pas encore inscrit ? C'est très simple et gratuit.