Générateur de chaîne aléatoire PHP : fonctionnement interne expliqué
\n\nChaque développeur a déjà été confronté à la tâche de générer une chaîne aléatoire. Pour des jetons, des mots de passe temporaires, des identifiants de session ou simplement pour des données de test. En PHP, il existe une dizaine de façons de le faire, mais laquelle est la bonne ? Et surtout — pourquoi ?
\n\nSur Stack Overflow, la question « PHP random string generator » a recueilli des milliers de vues et des centaines de réponses. Mais la plupart ne sont que des extraits de code prêts à l'emploi sans explication. Aujourd'hui, nous allons explorer les coulisses de PHP et comprendre comment fonctionnent réellement les générateurs de chaînes aléatoires, en quoi rand() diffère de random_int() et pourquoi votre mot de passe « aléatoire » pourrait ne pas l'être du tout.
Qu'est-ce que le « hasard » en PHP ?
\n\nEn programmation, il existe deux types de hasard : le pseudo-hasard et le hasard cryptographique. La différence entre eux est comparable à celle entre un dé à jouer et une calculatrice prévisible.
\n\nLes nombres pseudo-aléatoires (PRNG) sont générés par un algorithme basé sur une graine initiale (seed). Si vous connaissez la graine, vous connaissez toute la séquence. Pour des tâches simples (randomisation de couleur dans un design, données de test), cela suffit. Mais pour des jetons d'authentification et des mots de passe, c'est une catastrophe.
\n\nPHP propose plusieurs fonctions, chacune offrant un niveau de « hasard » différent :
\n\n- \n
rand()— PRNG classique, rapide mais prévisible \n mt_rand()— algorithme amélioré Mersenne Twister, plus rapide et avec une période plus longue \n random_int()etrandom_bytes()— générateurs cryptographiques (PHP 7+) \n openssl_random_pseudo_bytes()— une autre option cryptographique \n
Comment fonctionne l'extrait de code le plus populaire ?
\n\nVoici le code classique qui circule sur Internet :
\n\n<?php\nfunction generateRandomString($length = 10) {\n $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n $charactersLength = strlen($characters);\n $randomString = '';\n for ($i = 0; $i < $length; $i++) {\n $randomString .= $characters[rand(0, $charactersLength - 1)];\n }\n return $randomString;\n}\n?>\n\nÀ première vue, tout semble logique. On prend une chaîne de caractères, on sélectionne un index aléatoire, on répète. Mais analysons ce qui se passe réellement.
\n\nProblème n°1 : rand() et sa graine
\n\nLa fonction rand() en PHP utilise par défaut l'algorithme Linear Congruential Generator (LCG). C'est l'une des méthodes les plus anciennes et les plus prévisibles. Si vous n'appelez pas srand() avec une graine aléatoire, PHP initialise automatiquement le générateur avec l'heure actuelle (en microsecondes).
En connaissant l'heure exacte d'exécution du script (par exemple, à partir des logs du serveur), un attaquant peut reproduire toute la séquence de rand(). Pour un jeton de réinitialisation de mot de passe, c'est une porte ouverte au piratage.
Problème n°2 : Biais de probabilité (Bias)
\n\nMême sans considérations de sécurité, il y a un problème mathématique. Imaginez que rand(0, 61) (62 caractères dans la chaîne). PHP utilise en interne une plage de 0 à getrandmax() (généralement 2147483647). 2147483647 n'est pas divisible par 62. Le reste de la division est 31. Cela signifie que les 31 premiers nombres de la plage ont une probabilité légèrement plus élevée de sortir que les autres.
En pratique, la différence est minime, mais si vous avez besoin d'une chaîne aléatoire uniformément distribuée, rand() n'est pas le meilleur choix. random_int() résout ce problème en utilisant un algorithme qui garantit une distribution uniforme.
Générateur cryptographique : que se cache-t-il sous le capot ?
\n\nPHP 7 a introduit les fonctions random_int() et random_bytes(). Elles utilisent la source d'entropie du système :
- \