Sécurité des APIs
Pourquoi les APIs sont une cible privilégiée
Une API expose directement la logique métier de l’application. Contrairement à une interface web, elle est :
- Automatisable — un attaquant peut envoyer des milliers de requêtes en quelques secondes
- Prévisible — les endpoints suivent souvent des conventions lisibles (
/api/users/123) - Directement accessible — pas d’interface à contourner, on parle directement au serveur
Une API mal sécurisée est souvent plus facile à exploiter qu’une interface web, parce qu’elle a été conçue pour être efficace, pas pour être défensive.
Input validation — ne jamais faire confiance aux données entrantes
Tout ce qui arrive dans une requête API peut être manipulé : paramètres d’URL, corps de la requête, headers.
L’application doit vérifier que les données reçues :
- sont du bon type (un identifiant est un nombre, pas du texte libre)
- respectent les valeurs attendues (un statut est
actifouinactif, rien d’autre) - ne contiennent pas de caractères dangereux
Sans cette validation, on ouvre la porte aux injections (SQL, commandes système…) — voir le module OWASP A03.
Un formulaire web peut bloquer la saisie côté interface, mais rien n’empêche d’envoyer une requête directement à l’API en contournant le formulaire.
Rate limiting — limiter le débit des requêtes
Sans limite, une API peut recevoir autant de requêtes qu’un attaquant veut bien en envoyer. Cela permet :
- Brute force — tester des milliers de mots de passe sur un endpoint de login
- Scraping — extraire l’intégralité d’une base de données exposée via API
- Déni de service — saturer le serveur jusqu’à le rendre indisponible
Le rate limiting consiste à fixer un quota de requêtes autorisées sur une période donnée (ex. 100 requêtes par minute par utilisateur). Au-delà, les requêtes sont rejetées.
Les quotas peuvent s’appliquer par :
- Utilisateur authentifié
- Adresse IP
- Clé d’API
Authentification des APIs
Deux cas de figure distincts :
Un utilisateur appelle l’API (via une app ou un navigateur)
On utilise les mécanismes vus dans le module 1 : session, token JWT, OAuth. L’API vérifie que le token est valide et non expiré à chaque requête.
Une application appelle l’API (communication machine à machine)
Pas d’utilisateur humain impliqué. On utilise des clés d’API (API keys) ou le Client Credentials flow d’OAuth.
- Une clé d’API est un secret partagé : l’application appelante l’inclut dans chaque requête, le serveur la vérifie
- Elle doit être traitée comme un mot de passe : jamais exposée dans le code source, jamais dans une URL
Une clé d’API dans un dépôt Git public = compromission immédiate. Des outils scannent en permanence GitHub à la recherche de secrets exposés.
Exposition excessive de données
Une API retourne souvent plus d’informations que nécessaire.
Over-fetching : l’endpoint /api/users/123 retourne l’ensemble du profil (nom, email, rôle, date de naissance, numéro de téléphone…) alors que le client n’avait besoin que du nom.
Mass assignment : un endpoint qui accepte une mise à jour de profil prend en compte tous les champs envoyés, y compris des champs sensibles comme role ou isAdmin que l’utilisateur ne devrait pas pouvoir modifier.
Dans les deux cas, l’API expose plus de surface que nécessaire — ce qui facilite l’exploitation en cas de faille.
Endpoints oubliés
Les APIs évoluent : des versions se succèdent, des endpoints sont dépréciés mais jamais désactivés.
L’ancienne version
/api/v1/userspeut ne plus être maintenue, donc plus surveillée et plus protégée — mais elle fonctionne encore.
C’est une surface d’attaque invisible : personne ne la documente, personne ne la surveille, mais elle reste accessible.
Bonne pratique : tenir un inventaire des endpoints exposés et désactiver explicitement ce qui n’est plus utilisé.
Vue d’ensemble : les couches de sécurité d’une requête API
flowchart TD
Client(["🖥️ Client"]) -->|"HTTPS / TLS — chiffrement du transport"| CDN
subgraph Infra ["🌐 Infrastructure réseau"]
CDN["CDN / Load Balancer\nAnti-DDoS"]
CDN --> WAF["WAF · Firewall\nRègles, filtrage IP, blocklists"]
WAF --> RATE["Rate Limiting\nQuota par IP / clé d'API / utilisateur"]
end
subgraph GW ["🚪 API Gateway"]
RATE --> AUTHN["Authentification\nJWT · Session · API Key\nSignature valide ? Token expiré ?"]
end
subgraph APP ["⚙️ Application"]
AUTHN --> AUTHZ["Autorisation\nRBAC · ABAC · ReBAC\nA-t-il le droit sur cette ressource ?"]
AUTHZ --> INPUT["Validation des entrées\nType · Format · Taille · Valeurs attendues"]
INPUT --> BIZ["Logique métier"]
end
subgraph DATA ["🗄️ Couche données"]
BIZ --> DB[("Base de données\nRequêtes préparées — anti-injection\nChiffrement au repos")]
end
WAF -->|"Règle déclenchée"| E1["❌ 403 Forbidden"]
RATE -->|"Quota dépassé"| E2["❌ 429 Too Many Requests"]
AUTHN -->|"Token absent ou invalide"| E3["❌ 401 Unauthorized"]
AUTHZ -->|"Permission refusée"| E4["❌ 403 Forbidden"]
INPUT -->|"Données invalides"| E5["❌ 400 Bad Request"] Chaque couche a une responsabilité distincte — aucune n’est suffisante seule. Ce module couvre les couches Gateway et Application, les plus directement liées au code et aux choix d’architecture.