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 actif ou inactif, 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/users peut 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.