En bref : pour la sécurité des API en PHP, cinq points comptent surtout : HTTPS uniquement, authentification sur chaque point d'accès non public, contrôle des autorisations pour chaque objet, limites strictes sur la méthode, le type de contenu et la taille de la requête, ainsi que des messages d'erreur brefs sans détails internes. S'y ajoutent la limitation du débit et un journal des événements pertinents pour la sécurité. Cela n'aide pas contre les failles de l'interpréteur PHP lui-même comme PHP2Shell ; il faut pour cela la mise à jour de PHP.
L'interface derrière le site web
De nombreuses entreprises ont examiné leurs sites web dans la semaine suivant le 21 octobre 2026. Les interfaces qui se trouvent derrière figuraient plus rarement sur la liste. Or c'est précisément là que passent des opérations sensibles : l'application du portail client récupère des factures, le système de gestion des marchandises écrit les stocks dans la boutique, un partenaire signale des commandes par webhook. Ces API ont souvent été construites vite, pour un seul usage, puis plus jamais regardées.
Une API n'a pas d'interface qui rende les erreurs visibles. Un contrôle d'autorisation manquant ne frappe personne au quotidien, tant que tous les clients ne demandent que ce qu'ils doivent. Un attaquant, lui, essaie précisément ce qui n'est pas prévu.
La première étape est donc un état des lieux. Quels points d'accès existent, au juste ? On trouve souvent d'anciennes versions comme /api/v1/, qui n'ont jamais été désactivées après le passage à /v2/, des points d'accès de test issus du développement ou une description d'interface accessible publiquement qui énumère des fonctions internes. Tout point d'accès qui n'est plus nécessaire devrait être désactivé. Chacun de ceux qui restent a besoin d'un responsable.
Sécurité des API en PHP : les règles de base
L'aide-mémoire OWASP REST Security rassemble des règles éprouvées. Pour les projets PHP, elles se traduisent en une courte liste :
- HTTPS uniquement. Les jetons et les identifiants ne doivent jamais être transmis sans chiffrement.
- Chaque point d'accès contrôle lui-même. L'authentification peut être centralisée, la décision d'accès se prend au point d'accès.
- Autorisation par objet. Pas seulement « est connecté », mais « a le droit d'accéder à précisément cet enregistrement ».
- Définir les méthodes autorisées. Ce qui n'est pas expressément autorisé est rejeté avec 405.
- Contrôler le type de contenu et la taille. Un type erroné donne 415, des requêtes trop volumineuses 413.
- Valider les saisies. Type, longueur, format et plage de valeurs, côté serveur.
- Aucun secret dans les URL. Jetons et clés relèvent des en-têtes, pas de la chaîne de requête.
- Erreurs brèves. Aucune trace de pile, aucun chemin ni message SQL vers le client.
- Limitation du débit. Trop de requêtes reçoivent la réponse 429.
- Isoler les points d'accès d'administration. Non accessibles publiquement ou seulement avec une authentification forte.
L'autorisation par objet : l'erreur la plus fréquente
Un exemple rend le problème concret. Un point d'accès fournit des factures sous /api/rechnungen/{id}. On vérifie qu'un jeton valide est présent. On ne vérifie pas que la facture appartient au client du jeton. Qui augmente de un son propre numéro de facture voit celle de son voisin.
La solution est simple et doit pourtant être appliquée à chaque endroit : la requête elle-même restreint au périmètre autorisé.
<?php
// N'autoriser que la méthode GET
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
header('Allow: GET');
exit;
}
$kundeId = $auth->kundeId(); // issu du jeton vérifié
$id = filter_var($routeId, FILTER_VALIDATE_INT);
if ($id === false) {
http_response_code(400);
exit;
}
// L'autorisation est dans la requête : uniquement ses propres factures
$stmt = $pdo->prepare('SELECT nummer, betrag, datum FROM rechnungen WHERE id = ? AND kunde_id = ?');
$stmt->execute([$id, $kundeId]);
$rechnung = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$rechnung) {
http_response_code(404); // ne pas révéler si l'ID existe
exit;
}
header('Content-Type: application/json');
echo json_encode($rechnung, JSON_THROW_ON_ERROR);
La requête avec paramètres protège en même temps contre l'injection SQL, voir Empêcher l'injection SQL en PHP. La façon dont PHP met à disposition les données de requête comme la méthode, les en-têtes et le corps est expliquée dans Superglobales : $_GET, $_POST, $_FILES et autres.
Bien vérifier les jetons
De nombreuses API fonctionnent avec des JSON Web Tokens. L'aide-mémoire OWASP fixe pour cela des règles claires : les jetons doivent être signés, les jetons non signés sont rejetés, et l'algorithme de vérification est défini sur le serveur, non repris du jeton. L'émetteur, le destinataire et la date d'expiration font également partie du contrôle. Utilisez pour cela une bibliothèque maintenue plutôt que des implémentations maison.
Les jetons propres, par exemple pour des webhooks ou des liens à usage unique, doivent provenir d'un générateur aléatoire cryptographiquement sûr et être comparés en temps constant. La façon de procéder en PHP est montrée dans Nombres aléatoires et jetons sûrs en PHP.
Donnez à chaque client et à chaque partenaire sa propre clé, avec précisément les droits dont il a besoin. Une clé exfiltrée peut alors être bloquée individuellement, sans interrompre toutes les autres connexions.
Poser des limites : taille, type et rythme
Une API ne devrait accepter que ce qu'elle attend. Cela commence par le type de contenu : un point d'accès qui traite du JSON rejette tout le reste. Vous limitez la taille maximale d'une requête à plusieurs niveaux, dans le serveur web et, dans PHP, via post_max_size. Cette limite fait aussi partie des mesures transitoires que php.net a citées à propos de PHP2Shell. La façon de la choisir judicieusement est décrite dans Limiter judicieusement post_max_size et upload_max_filesize.
La limitation du débit protège contre l'essai en série d'identifiants et contre la surcharge. Elle peut être mise en œuvre dans le serveur web, dans un proxy en amont ou dans l'application. L'important est que les limites s'appliquent par clé ou par utilisateur, et pas seulement par adresse IP.
Pour les API appelées directement depuis le navigateur s'ajoute CORS, c'est-à-dire les règles qui déterminent quels sites tiers peuvent envoyer des requêtes. Ne définissez ces en-têtes que si de tels appels sont réellement prévus, et indiquez individuellement les origines autorisées, au lieu d'admettre n'importe quelle origine. Un joker qui autorise tous les sites est presque toujours une erreur pour les points d'accès avec authentification.
Enfin, le journal : les connexions échouées, les jetons rejetés et les accès refusés relèvent du journal, pas les jetons eux-mêmes. Sans ces entrées, une attaque contre l'API reste invisible.
Comment PHP SOS aide-t-il concrètement ?
- Nous recensons toutes les interfaces de vos systèmes PHP, y compris celles qui sont oubliées ou internes, et vérifions lesquelles sont accessibles publiquement.
- Nous lisons la logique d'autorisation et testons de façon ciblée si des enregistrements d'autrui sont accessibles.
- Nous posons des limites de taille, de type et de rythme dans le serveur web et PHP, et les accordons avec vos clients.
- Pour un contrôle complet depuis l'extérieur, nous le combinons avec un audit de sécurité et test d'intrusion.
Conclusion : une API est aussi sûre que son point d'accès le plus négligé. Qui contrôle les autorisations par objet, pose des limites claires et garde les erreurs brèves ferme les failles les plus courantes, bien avant que quelqu'un ne les recherche de façon ciblée.
Questions fréquentes
Une clé d'API suffit-elle comme protection ?
Pas pour des données sensibles. Une clé d'API identifie généralement une application, pas un utilisateur, et se transmet facilement. L'aide-mémoire OWASP REST Security conseille de ne pas utiliser les clés d'API comme seule protection pour des ressources sensibles.
Qu'est-ce qu'une autorisation par objet et pourquoi manque-t-elle si souvent ?
Il s'agit de vérifier si l'utilisateur connecté a le droit de voir ou de modifier précisément cet enregistrement. Elle manque souvent parce que les développeurs vérifient seulement que quelqu'un est connecté. Il suffit alors de modifier un identifiant dans l'URL pour obtenir les données d'autrui.
Une API bien sécurisée protège-t-elle contre PHP2Shell ?
Non. PHP2Shell se trouve dans l'interpréteur PHP et agit dans les modes d'exécution concernés avant même que votre code ne s'exécute. Seule une mise à jour de PHP avec redémarrage y remédie. Des limites de taille pour les requêtes restent pertinentes et font aussi partie des mesures transitoires citées par php.net.
Quels codes d'état une API devrait-elle renvoyer en cas d'erreur de sécurité ?
Les codes usuels sont 401 sans authentification valide, 403 en cas d'autorisation manquante, 405 pour une méthode non autorisée, 413 pour une requête trop volumineuse, 415 pour un type de contenu erroné et 429 pour trop de requêtes. La réponse elle-même reste brève et sans détails internes.