Sécuriser une API en production : authentification, rate limiting, CORS et bonnes pratiques
Une API exposée est attaquée en continu, dès sa mise en ligne. La sécuriser, c'est empiler plusieurs couches : chiffrement, auth, limitation, validation. Voici le guide complet.
Une API exposée sur Internet est attaquée en continu. Scans automatisés, credential stuffing, recherche de routes oubliées, injections, vol de jetons et consommation abusive de ressources commencent souvent quelques minutes après sa mise en ligne. Une API peu connue n’est donc pas une API invisible.
La sécurisation repose sur plusieurs couches complémentaires : chiffrement, authentification, autorisation, limitation du trafic, validation des données, supervision et maintenance. Aucun mécanisme isolé ne suffit. Une infrastructure protégée contre les attaques réseau reste vulnérable si un endpoint accepte des permissions excessives ou des entrées non contrôlées.
Imposer HTTPS partout
Une API de production ne doit jamais accepter de trafic HTTP en clair. Sans TLS, les identifiants, clés API, jetons et données métier peuvent être interceptés ou modifiés pendant leur transport.
Le chiffrement TLS peut être terminé par un reverse proxy comme Nginx ou Traefik, placé devant l’application. Le port HTTP doit uniquement servir à rediriger vers HTTPS. Les certificats doivent être renouvelés automatiquement et les anciennes versions de TLS désactivées.
L’en-tête HSTS demande aux navigateurs de contacter le domaine exclusivement en HTTPS :
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
N’activez includeSubDomains que si tous les sous-domaines sont compatibles avec HTTPS. Testez également les renouvellements de certificat et les redirections avant la mise en production.
Distinguer authentification et autorisation
L’authentification, ou authn, vérifie l’identité de l’appelant. L’autorisation, ou authz, détermine ce que cette identité a le droit de faire. Un utilisateur correctement authentifié ne doit pas pouvoir consulter les ressources d’un autre compte ou appeler une route réservée aux administrateurs.
Les clés API conviennent aux échanges service-à-service lorsque l’identité d’un service suffit. Chaque client doit recevoir une clé distincte, associée à des permissions limitées. Évitez une clé globale partagée entre plusieurs applications, car sa révocation devient difficile.
Pour les utilisateurs, OAuth2 ou des jetons JWT sont généralement plus adaptés. Un JWT doit avoir une durée de vie courte. L’API doit vérifier sa signature, son expiration, son émetteur, son audience et l’algorithme attendu. Elle ne doit jamais accepter l’algorithme indiqué par le jeton sans le comparer à une liste autorisée.
Le jeton est transmis dans l’en-tête d’authentification :
Authorization: Bearer <jeton_court_et_signe>
Ne placez jamais un secret durable dans une application mobile, un script distribué ou du JavaScript exécuté dans le navigateur. Tout secret livré au client doit être considéré comme récupérable.
Chaque endpoint doit contrôler les scopes, rôles et droits sur la ressource demandée. Appliquez le principe du moindre privilège : une identité ne reçoit que les permissions nécessaires, pour la durée nécessaire.
Mettre en place un rate limiting
Le rate limiting réduit les tentatives de brute force, le credential stuffing, le scraping et les consommations accidentelles ou malveillantes. Il peut être appliqué par adresse IP, clé API, utilisateur ou combinaison de ces critères.
La limite doit tenir compte du type de route. Une connexion peut être limitée à quelques tentatives par minute, tandis qu’un endpoint de lecture supportera davantage de requêtes. Pour une opération coûteuse, comme une recherche complexe ou un service IA, ajoutez aussi des quotas métier par compte.
Exemple Nginx avec une limite moyenne de dix requêtes par seconde et une courte tolérance aux rafales :
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_req_status 429;
proxy_pass http://application;
}
}
Une requête refusée doit recevoir le statut 429 Too Many Requests. Vous pouvez aussi fournir Retry-After afin d’indiquer quand réessayer. Dans une architecture distribuée, centralisez les compteurs ou utilisez une passerelle capable de partager leur état.
Les adresses IP ne suffisent pas toujours. Plusieurs utilisateurs légitimes peuvent partager une même sortie réseau, tandis qu’un attaquant peut répartir ses requêtes entre de nombreuses adresses.
Valider toutes les entrées
Toute donnée reçue est non fiable, y compris les en-têtes, paramètres de route, chaînes de requête, fichiers et objets JSON. Définissez un schéma pour chaque endpoint et refusez les champs inconnus lorsque cela est possible.
Contrôlez notamment :
- le type et le format des valeurs ;
- les longueurs minimales et maximales ;
- les plages numériques ;
- les listes de valeurs autorisées ;
- la profondeur des objets ;
- le nombre d’éléments dans les tableaux ;
- la taille totale du payload.
Les requêtes SQL doivent toujours être paramétrées. Ne construisez jamais une commande SQL par concaténation avec une valeur fournie par le client. La même prudence s’applique aux commandes système, moteurs de modèles, recherches et chemins de fichiers.
Configurez une taille maximale de requête au niveau du reverse proxy :
client_max_body_size 2m;
La validation doit être effectuée côté serveur, même si l’interface cliente possède déjà ses propres contrôles.
Configurer CORS précisément
CORS indique aux navigateurs quelles origines peuvent appeler une API depuis du code frontend. N’autorisez que les domaines nécessaires et comparez l’origine reçue à une liste exacte de confiance.
Exemple d’en-têtes pour un frontend autorisé :
Access-Control-Allow-Origin: https://app.exemple.fr
Access-Control-Allow-Methods: GET, POST, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Credentials: true
Vary: Origin
N’associez jamais Access-Control-Allow-Origin: * à l’utilisation de credentials. Si plusieurs origines sont permises, validez l’en-tête Origin côté serveur avant de le recopier dans la réponse. Une réflexion automatique de n’importe quelle origine annule la restriction.
Traitez correctement les requêtes préliminaires OPTIONS, sans exiger inutilement une authentification lorsque le navigateur vérifie seulement les permissions CORS.
CORS reste une protection appliquée par les navigateurs. Il ne bloque ni un script serveur, ni un client HTTP, ni un attaquant utilisant directement l’API. Ce n’est donc pas un pare-feu et cela ne remplace jamais l’authentification.
Protéger les secrets et la configuration
Les secrets ne doivent jamais apparaître en dur dans le code, les images de conteneur, les fichiers publics ou Git. Utilisez des variables d’environnement ou un gestionnaire de secrets avec des droits d’accès contrôlés.
Prévoyez une procédure de rotation. Une clé compromise doit pouvoir être remplacée sans interruption prolongée. Pour faciliter la transition, l’application peut accepter temporairement l’ancienne et la nouvelle clé, puis révoquer l’ancienne.
Les clés API stockées en base doivent être hashées avec une fonction adaptée, comme les mots de passe. Conservez éventuellement un préfixe non secret pour identifier rapidement la clé à vérifier. Affichez la valeur complète uniquement lors de sa création.
Séparez les secrets de développement, de préproduction et de production. Un compte technique doit disposer de permissions minimales et ne jamais partager les identifiants d’un administrateur humain.
Ajouter des en-têtes de sécurité
En complément de HSTS, certains en-têtes réduisent les comportements ambigus des clients :
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
Pour une API purement JSON, vérifiez aussi que chaque réponse utilise le bon Content-Type. Si le même domaine expose des pages web, une Content Security Policy peut limiter les sources autorisées pour les scripts, styles et connexions réseau. Elle doit être construite selon les besoins réels de l’application, puis testée avant d’être rendue bloquante.
Journaliser et superviser sans exposer les données
Journalisez les accès, statuts HTTP, temps de réponse, échecs d’authentification et décisions de rate limiting. Ajoutez un identifiant de corrélation afin de suivre une requête entre plusieurs services.
Ne journalisez jamais les mots de passe, clés API, jetons complets, cookies de session ou payloads sensibles. Masquez les en-têtes d’autorisation et limitez les données personnelles collectées. Les adresses IP pouvant constituer des données personnelles, définissez une durée de conservation, des accès restreints et une finalité conforme au RGPD.
Des alertes doivent détecter les hausses de réponses 401, 403, 429 et 5xx, les pics de latence ou les volumes inhabituels par identité. Un tableau de bord sans seuils ni alertes ne suffit pas en cas d’incident nocturne.
Maîtriser les messages d’erreur
Une réponse d’erreur ne doit pas révéler de stack trace, requête SQL, chemin local, secret, version précise d’un composant ou détail d’infrastructure. Retournez un message générique au client et conservez le diagnostic détaillé dans les journaux internes.
Utilisez des statuts cohérents : 400 pour une requête invalide, 401 lorsque l’authentification manque ou échoue, 403 lorsque l’identité n’a pas la permission et 404 lorsque la ressource n’existe pas. Dans certains cas, répondre 404 plutôt que 403 évite de confirmer l’existence d’une ressource sensible.
Maintenir les dépendances et préparer les incidents
Inventoriez les bibliothèques, images de conteneur et composants du reverse proxy. Automatisez l’analyse des vulnérabilités et appliquez rapidement les correctifs critiques. Supprimez les dépendances abandonnées et verrouillez les versions afin de rendre les déploiements reproductibles.
Testez régulièrement les routes sensibles, les contrôles d’accès entre comptes, les expirations de jetons, les limites de payload et les scénarios de révocation. Prévoyez aussi une procédure d’incident : identifier une clé compromise, la révoquer, analyser les journaux, informer les personnes concernées et restaurer un service sain.
Combiner protection réseau et sécurité applicative
Chez TalCloud, les serveurs situés en France, le stockage NVMe, l’accompagnement humain et l’Anti-DDoS Netrix constituent une base d’hébergement adaptée aux exigences opérationnelles et au contexte RGPD. Les offres VPS démarrent à 4,99 € par mois pour les équipes souhaitant maîtriser leur environnement de déploiement.
L’Anti-DDoS Netrix protège la couche réseau contre des volumes de trafic hostiles, mais il ne peut pas décider si un utilisateur authentifié abuse d’un endpoint ou si une route applique les mauvaises permissions. La défense efficace associe donc protection réseau, reverse proxy durci, contrôles applicatifs, supervision et procédures de réponse éprouvées.