Percez les secrets de CORS (Cross-Origin Resource Sharing) et apprenez à activer en toute sécurité les requêtes inter-domaines dans vos applications web. Ce guide complet couvre les bases jusqu'aux configurations avancées, assurant une communication fluide et sécurisée entre les différentes origines.
Démystifier CORS : Un guide complet sur le partage des ressources entre origines multiples
Dans le web interconnecté d'aujourd'hui, les applications ont souvent besoin d'accéder à des ressources provenant de différentes origines. C'est là que le Partage des ressources entre origines multiples (CORS) entre en jeu. CORS est un mécanisme de sécurité crucial qui régit la manière dont les navigateurs web gèrent les requêtes d'une origine (domaine, protocole et port) vers une origine différente. Comprendre CORS est essentiel pour tout développeur web afin de construire des applications web sécurisées et fonctionnelles.
Qu'est-ce que la politique de même origine (Same-Origin Policy) ?
Avant de plonger dans CORS, il est important de comprendre la politique de même origine (Same-Origin Policy - SOP). La SOP est un mécanisme de sécurité fondamental implémenté dans les navigateurs web. Son but est d'empêcher les scripts malveillants d'un site web d'accéder à des données sensibles sur un autre site web. Une origine est définie par la combinaison du protocole (par ex., HTTP ou HTTPS), du domaine (par ex., example.com) et du numéro de port (par ex., 80 ou 443). Deux URL sont considérées comme ayant la même origine si elles partagent le même protocole, le même domaine et le même port.
Exemple :
http://example.com/app1
ethttp://example.com/app2
- Même origine (même protocole, domaine et port)https://example.com/app1
ethttp://example.com/app1
- Origine différente (protocole différent)http://example.com:8080/app1
ethttp://example.com/app1
- Origine différente (port différent)http://sub.example.com/app1
ethttp://example.com/app1
- Origine différente (sous-domaine différent – considéré comme un domaine différent)
La SOP empêche les scripts d'accéder à des ressources d'une origine différente, à moins que des mesures spécifiques, telles que CORS, ne soient en place pour l'autoriser.
Pourquoi CORS est-il nécessaire ?
Bien que la politique de même origine soit vitale pour la sécurité, elle peut aussi être restrictive. De nombreuses applications web modernes dépendent de la récupération de données depuis des serveurs différents, comme des API ou des réseaux de diffusion de contenu (CDN). CORS offre un moyen contrôlé d'assouplir la SOP et d'autoriser les requêtes légitimes entre origines multiples tout en maintenant la sécurité.
Imaginez un scénario où une application web hébergée sur http://example.com
a besoin de récupérer des données d'un serveur d'API hébergé sur http://api.example.net
. Sans CORS, le navigateur bloquerait cette requête à cause de la SOP. CORS permet au serveur d'API de spécifier explicitement quelles origines sont autorisées à accéder à ses ressources, permettant ainsi à l'application web de fonctionner correctement.
Comment fonctionne CORS : Les bases
CORS fonctionne grâce à une série d'en-têtes HTTP échangés entre le client (navigateur) et le serveur. Le serveur utilise ces en-têtes pour informer le navigateur s'il est autorisé à accéder à la ressource demandée. L'en-tête HTTP clé impliqué est Access-Control-Allow-Origin
.
Scénario 1 : Requête simple
Une « requête simple » est une requête GET, HEAD ou POST qui remplit des critères spécifiques (par ex., l'en-tête Content-Type
est l'un des suivants : application/x-www-form-urlencoded
, multipart/form-data
, ou text/plain
). Dans ce cas, le navigateur envoie la requête directement au serveur, et le serveur répond avec l'en-tête Access-Control-Allow-Origin
.
Requête du client (depuis http://example.com) :
GET /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
Réponse du serveur (depuis http://api.example.net) :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Content-Type: application/json
{
"data": "Quelques données du serveur"
}
Dans cet exemple, le serveur répond avec Access-Control-Allow-Origin: http://example.com
, indiquant que les requêtes provenant de http://example.com
sont autorisées. Si l'origine dans la requête ne correspond pas à la valeur de l'en-tête Access-Control-Allow-Origin
(ou si l'en-tête est absent), le navigateur bloquera la réponse et empêchera le script côté client d'accéder aux données.
Scénario 2 : Requête preflight (pour les requêtes complexes)
Pour les requêtes plus complexes, telles que celles utilisant des méthodes HTTP comme PUT, DELETE, ou celles avec des en-têtes personnalisés, le navigateur effectue une requête « preflight » en utilisant la méthode HTTP OPTIONS. Cette requête preflight demande la permission au serveur avant d'envoyer la requête réelle. Le serveur répond avec des en-têtes qui spécifient quelles méthodes, quels en-têtes et quelles origines sont autorisés.
Requête preflight du client (depuis http://example.com) :
OPTIONS /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Réponse du serveur (depuis http://api.example.net) :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header, Content-Type
Access-Control-Max-Age: 3600
Explication des en-têtes :
Access-Control-Allow-Origin: http://example.com
- Indique que les requêtes depuishttp://example.com
sont autorisées.Access-Control-Allow-Methods: GET, PUT, DELETE
- Spécifie les méthodes HTTP autorisées pour les requêtes inter-origines.Access-Control-Allow-Headers: X-Custom-Header, Content-Type
- Liste les en-têtes personnalisés autorisés dans la requête réelle.Access-Control-Max-Age: 3600
- Spécifie la durée (en secondes) pendant laquelle la réponse preflight peut être mise en cache par le navigateur. Cela aide à réduire le nombre de requêtes preflight.
Si la réponse preflight du serveur indique que la requête est autorisée, le navigateur procède à la requête réelle. Sinon, le navigateur bloque la requête.
Requête réelle du client (depuis http://example.com) :
PUT /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
X-Custom-Header: some-value
Content-Type: application/json
{
"data": "Quelques données à mettre à jour"
}
Réponse du serveur (depuis http://api.example.net) :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Content-Type: application/json
{
"status": "Données mises à jour avec succès"
}
En-têtes CORS courants
Voici une description des principaux en-têtes CORS que vous devez comprendre :
Access-Control-Allow-Origin
: Cet en-tête est le plus fondamental. Il spécifie la ou les origines autorisées à accéder à la ressource. Les valeurs possibles incluent :- Une origine spécifique (par ex.,
http://example.com
). *
(joker) : Cela autorise les requêtes de n'importe quelle origine. À utiliser avec prudence, car cela peut compromettre la sécurité si des données sensibles sont impliquées. Il faut généralement l'éviter dans les environnements de production.
- Une origine spécifique (par ex.,
Access-Control-Allow-Methods
: Cet en-tête spécifie les méthodes HTTP (par ex., GET, POST, PUT, DELETE) qui sont autorisées pour les requêtes inter-origines. Il est utilisé dans la réponse preflight.Access-Control-Allow-Headers
: Cet en-tête liste les en-têtes personnalisés qui sont autorisés dans les requêtes inter-origines. Il est également utilisé dans la réponse preflight.Access-Control-Allow-Credentials
: Cet en-tête indique si le serveur autorise l'inclusion d'informations d'identification (par ex., cookies, en-têtes d'autorisation) dans les requêtes inter-origines. Il doit être défini surtrue
si vous avez besoin d'envoyer des informations d'identification. Côté client, vous devez également définirwithCredentials = true
sur l'objet XMLHttpRequest.Access-Control-Expose-Headers
: Par défaut, les navigateurs n'exposent qu'un ensemble limité d'en-têtes de réponse (par ex.,Cache-Control
,Content-Language
,Content-Type
,Expires
,Last-Modified
,Pragma
) aux scripts côté client. Si vous souhaitez exposer d'autres en-têtes, vous devez les lister dans l'en-têteAccess-Control-Expose-Headers
.Access-Control-Max-Age
: Cet en-tête spécifie la durée maximale (en secondes) pendant laquelle un navigateur peut mettre en cache la requête preflight. Une valeur plus longue réduit le nombre de requêtes preflight, améliorant ainsi les performances.
CORS dans différents langages côté serveur
La mise en œuvre de CORS implique généralement de configurer votre application côté serveur pour qu'elle envoie les en-têtes CORS appropriés. Voici des exemples de la manière de le faire dans divers langages et frameworks :
Node.js avec Express
Vous pouvez utiliser le package middleware cors
:
const express = require('express');
const cors = require('cors');
const app = express();
// Activer CORS pour toutes les origines (À UTILISER AVEC PRUDENCE EN PRODUCTION)
app.use(cors());
// Alternativement, configurer CORS pour des origines spécifiques
// app.use(cors({
// origin: 'http://example.com'
// }));
app.get('/data', (req, res) => {
res.json({ message: 'Ceci est activé par CORS pour toutes les origines !' });
});
app.listen(3000, () => {
console.log('Le serveur tourne sur le port 3000');
});
Python avec Flask
Vous pouvez utiliser l'extension Flask-CORS
:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
# Alternativement, configurer CORS pour des origines spécifiques
# CORS(app, resources={r"/api/*": {"origins": "http://example.com"}})
@app.route("/data")
def hello():
return {"message": "Ceci est activé par CORS pour toutes les origines !"}
if __name__ == '__main__':
app.run(debug=True)
Java avec Spring Boot
Vous pouvez configurer CORS dans votre application Spring Boot en utilisant des annotations ou des classes de configuration :
Utilisation d'annotations :
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Autoriser les requêtes depuis http://example.com
public class DataController {
@GetMapping("/data")
public String getData() {
return "Ceci est activé par CORS pour http://example.com !";
}
}
Utilisation de la configuration :
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/data")
.allowedOrigins("http://example.com") // Autoriser les requêtes depuis http://example.com
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}
PHP
"Ceci est activé par CORS pour http://example.com !");
echo json_encode($data);
?>
CORS et considérations de sécurité
Bien que CORS permette les requêtes inter-origines, il est crucial de le mettre en œuvre de manière sécurisée. Voici quelques considérations importantes :
- Évitez d'utiliser
*
pourAccess-Control-Allow-Origin
en production : Cela autorise les requêtes de n'importe quelle origine, ce qui peut constituer un risque de sécurité. Spécifiez plutôt explicitement les origines qui sont autorisées à accéder à vos ressources. - Validez l'en-tête
Origin
côté serveur : Même si vous utilisez un framework qui gère la configuration CORS, il est de bonne pratique de valider l'en-têteOrigin
côté serveur pour s'assurer que la requête provient d'une origine attendue. - Soyez attentif à
Access-Control-Allow-Credentials
: Si vous utilisez des informations d'identification (par ex., cookies, en-têtes d'autorisation), assurez-vous de définirAccess-Control-Allow-Credentials: true
côté serveur etwithCredentials = true
côté client. Cependant, sachez que l'utilisation deAccess-Control-Allow-Origin: *
n'est pas autorisée lorsqueAccess-Control-Allow-Credentials
est défini surtrue
. Vous devez spécifier explicitement les origines autorisées. - Configurez correctement
Access-Control-Allow-Methods
etAccess-Control-Allow-Headers
: N'autorisez que les méthodes HTTP et les en-têtes nécessaires au bon fonctionnement de votre application. Cela aide à réduire la surface d'attaque. - Utilisez HTTPS : Utilisez toujours HTTPS pour vos applications web et vos API afin de protéger les données en transit.
Dépannage des problèmes CORS
Les problèmes CORS peuvent être frustrants à déboguer. Voici quelques problèmes courants et comment les résoudre :
- « Aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée » : C'est l'erreur CORS la plus courante. Cela signifie que le serveur n'envoie pas l'en-tête
Access-Control-Allow-Origin
dans sa réponse. Vérifiez attentivement votre configuration côté serveur pour vous assurer que l'en-tête est envoyé correctement. - « La réponse à la requête preflight ne passe pas le contrôle d'accès : elle n'a pas le statut HTTP ok » : Cette erreur indique que la requête preflight a échoué. Cela peut se produire si le serveur n'est pas configuré pour gérer les requêtes OPTIONS ou si les en-têtes
Access-Control-Allow-Methods
ouAccess-Control-Allow-Headers
ne sont pas configurés correctly. - « La valeur de l'en-tête 'Access-Control-Allow-Origin' dans la réponse n'est pas égale à l'origine de la requête » : Cette erreur signifie que l'origine de la requête ne correspond pas à la valeur de l'en-tête
Access-Control-Allow-Origin
. Assurez-vous que le serveur envoie la bonne origine dans la réponse. - Mise en cache du navigateur : Parfois, les navigateurs peuvent mettre en cache les réponses CORS, ce qui peut entraîner un comportement inattendu. Essayez de vider le cache de votre navigateur ou d'utiliser un autre navigateur pour voir si cela résout le problème. Vous pouvez également utiliser l'en-tête
Access-Control-Max-Age
pour contrôler la durée de mise en cache de la réponse preflight par le navigateur.
Outils de débogage :
- Outils de développement du navigateur : Utilisez les outils de développement du navigateur (généralement accessibles en appuyant sur F12) pour inspecter les requêtes et réponses réseau. Recherchez les en-têtes et les messages d'erreur liés à CORS.
- Vérificateurs CORS en ligne : Il existe des outils en ligne qui peuvent vous aider à tester votre configuration CORS. Ces outils envoient une requête à votre serveur et analysent les en-têtes de réponse pour identifier les problèmes potentiels.
Scénarios CORS avancés
Bien que les concepts de base de CORS soient relativement simples, il existe des scénarios plus avancés à prendre en compte :
- CORS avec des sous-domaines : Si vous devez autoriser les requêtes de plusieurs sous-domaines (par ex.,
app1.example.com
,app2.example.com
), vous ne pouvez pas simplement utiliser un joker comme*.example.com
dans l'en-têteAccess-Control-Allow-Origin
. Au lieu de cela, vous devrez générer dynamiquement l'en-têteAccess-Control-Allow-Origin
en fonction de l'en-têteOrigin
de la requête. N'oubliez pas de valider l'origine par rapport à une liste blanche de sous-domaines autorisés pour éviter les vulnérabilités de sécurité. - CORS avec plusieurs origines : Si vous devez autoriser les requêtes de plusieurs origines spécifiques, vous ne pouvez pas spécifier plusieurs origines dans l'en-tête
Access-Control-Allow-Origin
(par ex.,Access-Control-Allow-Origin: http://example.com, http://another.com
est invalide). Au lieu de cela, vous devrez générer dynamiquement l'en-têteAccess-Control-Allow-Origin
en fonction de l'en-têteOrigin
de la requête. - CORS et les CDN : Lorsque vous utilisez un CDN pour servir votre API, vous devez configurer le CDN pour qu'il transmette l'en-tête
Origin
à votre serveur d'origine et pour qu'il mette en cache correctement l'en-têteAccess-Control-Allow-Origin
. Consultez la documentation de votre fournisseur de CDN pour des instructions spécifiques.
Bonnes pratiques CORS
Pour garantir une mise en œuvre sécurisée et efficace de CORS, suivez ces bonnes pratiques :
- Principe du moindre privilège : N'autorisez que l'ensemble minimal d'origines, de méthodes et d'en-têtes nécessaires au bon fonctionnement de votre application.
- Examinez régulièrement la configuration CORS : Au fur et à mesure que votre application évolue, examinez régulièrement votre configuration CORS pour vous assurer qu'elle est toujours appropriée et sécurisée.
- Utilisez un framework ou une bibliothèque : Tirez parti des frameworks ou des bibliothèques existants qui offrent un support CORS intégré. Cela peut simplifier la mise en œuvre et réduire le risque d'erreurs.
- Surveillez les violations de CORS : Mettez en place une surveillance pour détecter et répondre aux violations potentielles de CORS.
- Restez à jour : Tenez-vous au courant des dernières spécifications et recommandations de sécurité de CORS.
Conclusion
CORS est un mécanisme de sécurité essentiel qui permet des requêtes contrôlées entre origines multiples dans les applications web. Comprendre le fonctionnement de CORS et savoir comment le configurer correctement est essentiel pour tout développeur web. En suivant les directives et les bonnes pratiques décrites dans ce guide complet, vous pouvez construire des applications web sécurisées et fonctionnelles qui interagissent de manière transparente avec des ressources de différentes origines.
N'oubliez pas de toujours donner la priorité à la sécurité et d'éviter d'utiliser des configurations CORS trop permissives. En examinant attentivement les implications de sécurité de vos paramètres CORS, vous pouvez protéger vos applications et vos données contre les accès non autorisés.
Nous espérons que ce guide vous a aidé à démystifier CORS. Bon codage !