Développement de logiciels
Attaques de timing en PHP : Un exemple pratique - pourquoi `hash_equals()` compte ?
Tu veux un exemple réaliste d'une attaque par timing sur les jetons API dans Wordpress/Laravel/PHP ? Nous le traitons ici, avec des conseils et des mesures de bonnes pratiques contre les attaques par temporisation.
De nombreux développeurs font confiance à la comparaison simple avec === ou == lorsqu'ils vérifient les clés API, les jetons ou d'autres chaînes secrètes. A première vue, cela semble raisonnable - mais il y a un hic : les différences temporelles dans la comparaison peuvent être exploitées par les attaquants.
Cet article décrit un exemple réaliste de la manière dont se déroule conceptuellement une attaque par timing.
Le scénario réel (exemple simplifié)
Imagine qu'un microservice interne accepte des demandes avec un paramètre de requête token et le compare à un token d'API GitHub stocké dans l'environnement.
Code non sécurisé (simplifié) :
$expected = getenv('GITHUB_API_TOKEN') ;$provided = $_GET['token'] ? ? '';if ($provided === $expected) { } PHP
J'explique pourquoi cela pose problème dans la section suivante.
Comment fonctionne une attaque par timing ?
Si l'implémentation de la comparaison de jeton compare caractère par caractère et s'arrête immédiatement à la première erreur, alors une requête avec le premier caractère correct prend en moyenne un peu plus de temps.
Un premier caractère correct entraîne donc en moyenne un temps de traitement légèrement plus long qu'un premier caractère erroné. Il en va de même pour le deuxième caractère, etc.
Un attaquant en profite en testant tous les caractères possibles pour chaque position, en mesurant très souvent les temps de réponse et en les évaluant statistiquement. Le caractère avec le temps moyen/proportionnellement le plus long est probablement correct. Le jeton est ainsi reconstruit étape par étape.
Pourquoi hash_equals() est le bon choix ?
PHP fournit avec hash_equals() une fonction de comparaison de chaîne à temps constant (constant-time comparison). Elle garantit que le temps d'exécution de la comparaison ne dépend pas de préfixes communs - tant que les deux chaînes ont la même longueur.
Alternative sûre (pour Laravel, PHP, Wordpress) :
$expected = getenv('GITHUB_API_TOKEN') ; $provided = $_GET['token'] ? ? '';if (hash_equals($expected, $provided)) { } PHP
Note : hash_equals() n'est "indépendant du temps" que si les longueurs sont égales. Il est de bonne pratique de concevoir les tokens de manière à ce que la longueur soit constante (par exemple les HMAC, les UUID de longueur fixe ou les chaînes de caractères Base64 aléatoires de longueur fixe).
Tu savais ? Seul UUID-V4 est généré de manière complètement aléatoire et est donc souvent utilisé pour les jetons de sécurité. Comme il ne contient pas d'informations liées au temps ou à l'appareil, il offre une grande imprévisibilité et protège ainsi contre les attaques basées sur des modèles ou des prédictions. C'est précisément pour cette raison que UUID-V4 est le choix préféré lorsqu'il s'agit d'identifiants sûrs et difficiles à deviner.
Mesures de défense supplémentaires - plus que hash_equals()
- Longueur de token constante
Utilise des tokens de longueur fixe, par exemple UUID-V4. Si un attaquant devine la longueur, c'est moins utile tant que les caractères eux-mêmes sont sûrs.
- Limitation du taux
Limite les demandes par IP ou par compte. Les attaques par timing nécessitent de nombreuses mesures ; la limitation du taux augmente considérablement les efforts et les coûts pour l'attaquant.
- Enregistrement et surveillance
Détecte les modèles inhabituels (nombreuses tentatives de token, variation systématique de certains paramètres) et réagis de manière automatisée.
- Salt / HMAC / signatures
Utilise des tokens signés (HMAC avec clé secrète) ou des tokens OAuth au lieu de comparer ouvertement des clés statiques brutes.
- TLS/HTTPS
Le cryptage protège les canaux de communication - il n'empêche pas les attaques de timing sur les internautes du serveur, mais c'est une condition de base.
- Rotation des jetons
La faible durée de vie des tokens réduit l'utilité d'un tokens compromis.
Conclusion
Les attaques par timing ne sont pas un problème purement théorique - elles ont été étudiées dans la pratique et peuvent avoir de graves conséquences, surtout pour les points d'accès publics. La bonne nouvelle : pour les développeurs PHP/Laravel/Wordpress, la première contre-mesure est très simple :
- Remplacer les comparaisons directes de chaînes sensibles par
hash_equals().
- Veille à ce que la longueur des jetons soit constante, à ce que le taux soit limité, à ce que le journal soit enregistré et à ce que la gestion des jetons soit sécurisée.