Passer au contenu principal

🌐 Qu'est-ce que CORS ?

📖 Définition

CORS (Cross-Origin Resource Sharing, Partage de Ressources Cross-Origin) est un mécanisme de sécurité qui indique aux navigateurs d'autoriser l'accès aux ressources provenant d'origines (origin) différentes. Les navigateurs Web restreignent par défaut les requêtes de ressources cross-origin pour des raisons de sécurité, et CORS est la méthode pour permettre cela en toute sécurité.

🎯 Comprendre avec une Analogie

Système de Sécurité d'Appartement

Imaginez que vous vivez dans le Bâtiment A :

  • Même Origine (Same-Origin) : Appel depuis A-101 vers bureau A → Librement autorisé ✅
  • Cross-Origin : Appel depuis A-101 vers bureau B → Vérification de sécurité requise 🔒
  • Paramètre CORS : Le Bâtiment B dit "J'accepterai aussi les appels du Bâtiment A" → Appel autorisé ✅

CORS c'est comme ça, c'est la permission nécessaire pour accéder aux ressources d'autres bâtiments (origines) !

⚙️ Fonctionnement

1. Qu'est-ce que l'Origine (Origin) ?

L'origine est la combinaison du protocole, du domaine et du port :

https://www.example.com:443/page
│ │ │ │ │
│ │ │ │ └─ Chemin (non lié à l'origine)
│ │ │ └────── Port (443 si omis)
│ │ └────────────────── Domaine
│ └────────────────────── Protocole
└───────────────────────────── Origine (Origin)

2. Même Origine vs Cross-Origin

// Page actuelle : https://www.example.com

Même Origine (Same-Origin)
- https://www.example.com/page
- https://www.example.com/api/users

Cross-Origin
- http://www.example.com // Protocole différent
- https://api.example.com // Domaine différent
- https://www.example.com:8080 // Port différent

3. Processus de Requête CORS

Simple Request (Requête Simple)

1. Navigateur → Serveur : Envoyer requête
GET https://api.example.com/data
Origin: https://www.mysite.com

2. Serveur → Navigateur : Réponse
Access-Control-Allow-Origin: https://www.mysite.com

3. Navigateur : Vérifier réponse
- Si origine autorisée → Livrer données ✅
- Si non autorisée → Erreur CORS ❌

Preflight Request (Requête Preflight)

1. Navigateur → Serveur : Pré-vérification (OPTIONS)
OPTIONS https://api.example.com/data
Origin: https://www.mysite.com
Access-Control-Request-Method: POST

2. Serveur → Navigateur : Réponse d'autorisation
Access-Control-Allow-Origin: https://www.mysite.com
Access-Control-Allow-Methods: POST, GET
Access-Control-Max-Age: 3600

3. Navigateur → Serveur : Requête réelle (POST)
POST https://api.example.com/data

4. Serveur → Navigateur : Réponse de données

💡 Exemples Réels

Occurrence d'Erreur CORS

// Frontend (https://www.mysite.com)
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));

// ❌ Erreur console
// Access to fetch at 'https://api.example.com/users' from origin
// 'https://www.mysite.com' has been blocked by CORS policy:
// No 'Access-Control-Allow-Origin' header is present on the
// requested resource.

Activer CORS sur le Serveur

Express.js (Node.js)

const express = require('express');
const cors = require('cors');
const app = express();

// Méthode 1 : Autoriser toutes les origines (développement)
app.use(cors());

// Méthode 2 : Autoriser origine spécifique (production recommandé)
app.use(cors({
origin: 'https://www.mysite.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // Inclure cookies
maxAge: 3600 // Temps de cache Preflight (secondes)
}));

// Méthode 3 : Autoriser plusieurs origines
const allowedOrigins = [
'https://www.mysite.com',
'https://admin.mysite.com'
];

app.use(cors({
origin: function(origin, callback) {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
}
}));

// Point de terminaison API
app.get('/api/users', (req, res) => {
res.json({ users: ['Alice', 'Bob'] });
});

app.listen(3000);

Configuration Manuelle des En-têtes

app.use((req, res, next) => {
// Autoriser origine
res.header('Access-Control-Allow-Origin', 'https://www.mysite.com');

// Autoriser méthodes
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');

// Autoriser en-têtes
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');

// Autoriser informations d'authentification
res.header('Access-Control-Allow-Credentials', 'true');

// Gérer requête Preflight
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}

next();
});

Python Flask

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

# Autoriser toutes les origines
CORS(app)

# Autoriser seulement origine spécifique
CORS(app, resources={
r"/api/*": {
"origins": ["https://www.mysite.com"],
"methods": ["GET", "POST"],
"allow_headers": ["Content-Type"]
}
})

@app.route('/api/users')
def get_users():
return {'users': ['Alice', 'Bob']}

Configuration Nginx

server {
listen 80;
server_name api.example.com;

location /api {
# Ajouter en-têtes CORS
add_header 'Access-Control-Allow-Origin' 'https://www.mysite.com' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;

# Gérer requête Preflight
if ($request_method = 'OPTIONS') {
return 204;
}

proxy_pass http://backend;
}
}

🤔 Questions Fréquentes

Q1. Pourquoi CORS est-il nécessaire ?

R : Pour la sécurité. Sans CORS :

// Site malveillant (evil.com)
fetch('https://bank.com/api/transfer', {
method: 'POST',
credentials: 'include', // Inclut les cookies bancaires de l'utilisateur
body: JSON.stringify({
to: 'hacker-account',
amount: 1000000
})
});

// CORS bloque de telles attaques !

Q2. Comment résoudre les erreurs CORS ?

R : Selon la situation :

// 1. Si vous contrôlez le serveur → Ajouter en-têtes CORS (recommandé)
app.use(cors({ origin: 'https://frontend.com' }));

// 2. Si vous ne contrôlez pas le serveur → Utiliser serveur proxy
// package.json (Create React App)
{
"proxy": "https://api.example.com"
}

// 3. Environnement de développement → Middleware proxy
// setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
app.use('/api', createProxyMiddleware({
target: 'https://api.example.com',
changeOrigin: true
}));
};

// 4. Extension de navigateur (développement seulement !)
// Utiliser extensions comme "CORS Unblock"
// ⚠️ Ne jamais utiliser en production !

Q3. Quand utiliser credentials: 'include' ?

R : Lors de l'envoi de cookies ou d'informations d'authentification :

// Frontend
fetch('https://api.example.com/profile', {
credentials: 'include' // Inclure cookies
});

// Backend - Doit spécifier l'origine explicitement
app.use(cors({
origin: 'https://www.mysite.com', // Ne peut pas utiliser '*' !
credentials: true
}));

// ❌ Exemple incorrect
app.use(cors({
origin: '*', // Joker
credentials: true // Ne peut pas être utilisé avec credentials !
}));

Q4. Différence entre Simple Request et Preflight Request ?

R : Dépend des conditions :

// ✅ Simple Request (requête directe)
// - Méthode : GET, HEAD, POST
// - En-têtes : Seulement en-têtes de base comme Accept, Content-Type
// - Content-Type : text/plain, multipart/form-data,
// application/x-www-form-urlencoded

fetch('https://api.example.com/data', {
method: 'GET'
});

// ⚠️ Preflight Request (requête après preflight)
// - Méthode : PUT, DELETE, PATCH
// - En-têtes personnalisés : Authorization, etc.
// - Content-Type : application/json

fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // Nécessite Preflight
'Authorization': 'Bearer token' // Nécessite Preflight
},
body: JSON.stringify({ name: 'Alice' })
});

Q5. Différence entre CORS et CSRF ?

R : Concepts de sécurité complètement différents :

CORS (Cross-Origin Resource Sharing)
├─ Objectif : Autoriser l'accès aux ressources cross-origin
├─ Opération : Le navigateur bloque/autorise les réponses
└─ Solution : Ajouter en-têtes d'autorisation sur le serveur

CSRF (Cross-Site Request Forgery)
├─ Objectif : Empêcher les requêtes falsifiées
├─ Opération : Site malveillant envoie des requêtes
└─ Solution : Utiliser tokens CSRF

🎓 Prochaines Étapes

Après avoir compris CORS, apprenez :

  1. Qu'est-ce que HTTPS ? (document en préparation) - Autre sécurité Web importante
  2. Token JWT (document en préparation) - Méthode d'authentification API
  3. Qu'est-ce qu'une API ? - Concepts de base API

Outils de Débogage

// Vérifier dans les outils de développement du navigateur
// Onglet Network → Sélectionner requête → Onglet Headers

// Request Headers
Origin: https://www.mysite.com
Access-Control-Request-Method: POST

// Response Headers
Access-Control-Allow-Origin: https://www.mysite.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Max-Age: 3600

🎬 Résumé

CORS est un concept central de sécurité Web :

  • Origine : Combinaison de protocole + domaine + port
  • Politique Same-Origin : Bloque les origines différentes par défaut
  • CORS : Autorise les origines différentes en toute sécurité
  • Preflight : Pré-vérification pour requêtes complexes

Lorsque des erreurs CORS se produisent, ne paniquez pas - résolvez-les en toute sécurité en définissant les en-têtes appropriés sur le serveur ! 🌐✨