Sécuriser une API publique

3 min de lecture07 novembre 2026

Une API joignable depuis Internet reçoit des sondes automatisées en quelques minutes. La plupart échouent, mais elles cherchent exactement ce qu'un développement pressé laisse ouvert : une route sans jeton, un paramètre concaténé dans une requête SQL, un CORS trop large. La sécurité d'une API se construit en couches, chacune vérifiable séparément.

Terminer TLS avant l'application

L'application écoute sur 127.0.0.1, Nginx expose le port 443 et transmet la requête. L'application ne voit jamais le trafic public en clair et n'a pas à gérer les certificats :

Nginx
server {
    listen 443 ssl;
    server_name votre-domaine.fr;
    client_max_body_size 1m;

    location /api/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Installez le certificat avec sudo certbot --nginx -d votre-domaine.fr, puis vérifiez le renouvellement avec sudo certbot renew --dry-run. Activez HSTS seulement quand vous êtes certain de ne plus servir HTTP. Sur l'hébergement d'applications, vous ne gérez pas Nginx : appliquez les mêmes principes dans le code et contrôlez les en-têtes sur l'allocation fournie.

Authentifier et autoriser

Une clé d'API dans l'URL finit dans les journaux, l'historique du navigateur et les proxies. Placez-la dans l'en-tête Authorization, sur HTTPS uniquement. Si vous stockez des clés, stockez un hachage (Argon2id ou bcrypt), pas la valeur en clair, et affichez la clé une seule fois à sa création.

Distinguez authentification et autorisation : un jeton valide ne doit pas automatiquement tout permettre. Donnez des portées (read, write, admin) et vérifiez-les à chaque route. Préférez des jetons courts avec renouvellement, et prévoyez la révocation immédiate d'une clé compromise.

Limiter et valider

Un quota par adresse et par clé protège contre le balayage et l'abus :

Nginx
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

location /api/ {
    limit_req zone=api burst=20 nodelay;
    limit_req_status 429;
}

Validez chaque entrée côté serveur : type, longueur, format, champs autorisés. Refusez les champs inconnus plutôt que de les ignorer. Utilisez des requêtes paramétrées, jamais de concaténation SQL. Limitez la taille du corps avec client_max_body_size et imposez un délai de lecture pour éviter les connexions qui restent ouvertes.

CORS et journaux

CORS est une règle de navigateur, pas une authentification. Autorisez explicitement les origines connues ; n'utilisez pas * avec des identifiants. Répondez correctement aux requêtes OPTIONS et cachez la réponse preflight.

Journalisez la méthode, la route, le statut, la latence, un identifiant de requête et l'adresse, mais jamais le jeton, le mot de passe ni le corps complet. Un journal sans donnée personnelle reste exploitable et partageable. Alertez sur les pics de 401, 403 et 429 plutôt que sur chaque erreur.

Vérification

Bash
curl -sI https://votre-domaine.fr/api/health
curl -i https://votre-domaine.fr/api/health
curl -i -H "Authorization: Bearer jeton-invalide" https://votre-domaine.fr/api/health

Attendu : HTTPS valide, 401 sans jeton, 429 après une rafale. Vérifiez que les erreurs ne renvoient ni trace complète ni version de framework. Relisez les journaux après un test de charge : si vous ne pouvez pas expliquer une requête, le journal est incomplet.

Publicité

Cet article vous a-t-il aidé ?

À lire aussi