Protéger une API
Protection contre les attaques qui visent une API (Rate Limiting, CORS, etc.)
Notions théoriques
1. Introduction
Une API (Application Programming Interface) permet à des applications de communiquer entre elles.
Cependant, une API exposée sur Internet est vulnérable à plusieurs types d'attaques.
Il est donc essentiel de mettre en place des mécanismes de protection pour garantir sa sécurité et éviter les abus.
Les attaques courantes contre les API incluent :
- Attaques par force brute : Tentatives répétées d’authentification pour deviner des identifiants.
- Déni de service (DoS) : Envoi massif de requêtes pour surcharger le serveur.
- Cross-Origin Resource Sharing (CORS) mal configuré : Permet à des sites malveillants d’accéder aux ressources de l’API.
- Injection SQL/XSS : Tentatives d’exécution de code malveillant via les entrées utilisateur.
Pour protéger une API, plusieurs techniques peuvent être mises en place, notamment :
- Rate Limiting : Limiter le nombre de requêtes par utilisateur.
- CORS (Cross-Origin Resource Sharing) : Contrôler les domaines autorisés à accéder à l’API.
- Validation des entrées : Vérifier et filtrer les données envoyées à l’API.
- Authentification et autorisation : Restreindre l’accès aux ressources en fonction des utilisateurs.
Exemple pratique
Il est possible de sécuriser une API avec Express.js en mettant en place Rate Limiting et en configurant CORS.
1. Installation des dépendances
npm install express express-rate-limit cors helmet
2. Mise en place du serveur avec des protections
const express = require("express");
const rateLimit = require("express-rate-limit");
const cors = require("cors");
const helmet = require("helmet");
const app = express();
// Sécurisation des en-têtes HTTP
app.use(helmet());
// Configuration du Rate Limiting (100 requêtes par 15 minutes par IP)
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: "Trop de requêtes, veuillez réessayer plus tard."
});
app.use(limiter);
// Configuration de CORS (autoriser uniquement un domaine spécifique)
app.use(cors({ origin: "http://mon-site.com" }));
app.get("/", (req, res) => {
res.json({ message: "API sécurisée" });
});
app.listen(3000, () => {
console.log("Serveur démarré sur http://localhost:3000");
});
3. Explication du code :
- Helmet : Ajoute des en-têtes HTTP de sécurité.
- Rate Limiting : Limite le nombre de requêtes par IP pour éviter les abus.
- CORS : Restreint l’accès à l’API aux requêtes provenant de
http://mon-site.com
.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Sécurisation d'une API Express.js avec Rate Limiting et CORS
Ce TP a pour objectif de mettre en place une API sécurisée en utilisant :
- Rate Limiting pour limiter les requêtes
- et CORS pour restreindre les accès depuis des domaines spécifiques.
L’API sera développée avec Node.js et Express.js. Elle inclura :
- Une route publique accessible à tous.
- Une route protégée par un Rate Limiting strict.
- Une configuration de CORS pour autoriser uniquement certains domaines.
Étape 1 : Initialisation du projet
Avant d’écrire du code, il est nécessaire de préparer l’environnement de travail.
Instructions :
- Ouvrir un terminal et naviguer vers un dossier de travail.
- Créer un nouveau dossier pour le projet :
mkdir secure-api
cd secure-api
- Initialiser un projet Node.js :
npm init -y
- Installer les dépendances nécessaires :
npm install express express-rate-limit cors helmet dotenv
- Vérifier que les fichiers suivants sont bien présents dans le dossier :
package.json
(créé automatiquement)node_modules/
(dossier contenant les bibliothèques installées)
Vérifier si :
- Un projet Node.js est correctement initialisé.
- Les modules Express, express-rate-limit, cors, helmet et dotenv sont installés pour gérer la sécurité de l’API.
Étape 2 : Configuration de l’environnement
Pour éviter d’exposer des informations sensibles dans le code, il est recommandé d’utiliser un fichier .env
pour stocker les variables d’environnement.
Instructions :
- Créer un fichier
.env
à la racine du projet :
touch .env
- Ajouter les variables d’environnement suivantes :
PORT=4000
ALLOWED_ORIGIN=http://localhost:3000
RATE_LIMIT_WINDOW=10
RATE_LIMIT_MAX=50
- Modifier le fichier
package.json
pour ajouter un script de démarrage :
"scripts": {
"start": "node server.js"
}
Vérifier si :
- Un fichier
.env
est créé pour stocker les variables d’environnement. - Le fichier
package.json
est mis à jour avec un script de démarrage.
Étape 3 : Création du serveur Express.js
L’API doit être capable de répondre aux requêtes HTTP et d’appliquer des règles de sécurité.
Instructions :
- Créer un fichier
server.js
et ajouter le code suivant :
require("dotenv").config();
const express = require("express");
const rateLimit = require("express-rate-limit");
const cors = require("cors");
const helmet = require("helmet");
const app = express();
app.use(helmet());
// Configuration du Rate Limiting
const limiter = rateLimit({
windowMs: process.env.RATE_LIMIT_WINDOW * 60 * 1000,
max: process.env.RATE_LIMIT_MAX,
message: "Trop de requêtes, veuillez réessayer plus tard."
});
app.use(limiter);
// Configuration de CORS
app.use(cors({ origin: process.env.ALLOWED_ORIGIN }));
// Route publique
app.get("/", (req, res) => {
res.json({ message: "Bienvenue sur l'API sécurisée" });
});
// Route protégée
app.get("/protected", (req, res) => {
res.json({ message: "Vous avez accédé à une route protégée" });
});
// Démarrage du serveur
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Serveur démarré sur http://localhost:${PORT}`);
});
- Lancer le serveur :
npm start
- Vérifier que l’API fonctionne en envoyant une requête
GET
àhttp://localhost:4000/
.
Vérifier si :
- Un serveur Express.js est mis en place avec Rate Limiting et CORS.
- Une route publique
/
et une route protégée/protected
sont créées. - Le serveur démarre et écoute sur le port défini dans
.env
.
Étape 4 : Test du Rate Limiting
Le Rate Limiting empêche un utilisateur d’envoyer trop de requêtes en un temps limité.
Instructions :
- Ouvrir un terminal et exécuter la commande suivante plusieurs fois :
curl -X GET http://localhost:4000/protected
- Observer la réponse de l’API. Après 50 requêtes en 10 minutes, l’API doit renvoyer un message d’erreur :
{
"message": "Trop de requêtes, veuillez réessayer plus tard."
}
Vérifier si :
- Le Rate Limiting fonctionne correctement et bloque les requêtes excessives.
Étape 5 : Test de CORS
Le CORS contrôle quels domaines peuvent accéder à l’API.
Instructions :
- Ouvrir la console du navigateur (F12) et exécuter le code suivant dans l’onglet Console :
fetch("http://localhost:4000/protected")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("Erreur :", error));
- Observer la réponse :
- Si la requête est effectuée depuis
http://localhost:3000
, elle doit réussir. - Si la requête est effectuée depuis un autre domaine, une erreur CORS doit apparaître.
- Si la requête est effectuée depuis
Vérifier si :
- Le CORS est bien configuré et empêche les requêtes provenant de domaines non autorisés.
Étape 6 : Amélioration de la sécurité
Pour renforcer la sécurité de l’API, il est possible d’ajouter :
- Un middleware pour journaliser les requêtes suspectes.
- Un blocage des adresses IP suspectes.
Instructions :
- Installer un module de journalisation :
npm install morgan
- Modifier
server.js
pour ajouter un logger :
const morgan = require("morgan");
app.use(morgan("combined"));
- Relancer le serveur :
npm start
- Vérifier que toutes les requêtes sont enregistrées dans la console.
Vérifier si :
- Le journal des requêtes permet de surveiller les accès à l’API.
- Il est possible d’identifier les adresses IP suspectes.
Conclusion
Ce TP permet de comprendre comment protéger une API contre les attaques courantes en utilisant :
- Rate Limiting pour limiter les requêtes abusives.
- CORS pour restreindre l’accès aux domaines autorisés.
- Helmet pour renforcer la sécurité des en-têtes HTTP.
- Morgan pour journaliser les requêtes.
Des améliorations possibles :
- Ajouter une authentification par token JWT.
- Utiliser une base de données pour stocker les utilisateurs bloqués.
- Mettre en place un système de bannissement automatique pour les IP suspectes.
L’API est maintenant sécurisée et prête à être utilisée dans un projet plus avancé.