mt_rand() utilise l'algorithme mersennetwister pour renvoyer des entiers aléatoires. Tout le monde le sait, mais l'article suivant vous présente principalement les informations pertinentes sur la sécurité des nombres aléatoires mt_rand() en PHP. Vous avez besoin que vos amis puissent s'y référer. Apprenons avec l'éditeur ci-dessous.
Avant-propos
J'ai découvert de nombreuses vulnérabilités de sécurité liées à mt_rand() il y a quelque temps. Ils ont fondamentalement mal compris l'utilisation des nombres aléatoires. provoqué. Ici, je voudrais mentionner un autre piège du manuel du site officiel de PHP. Jetez un œil à l'introduction de mt_rand() : version chinoise ^cn version anglaise ^en Vous pouvez voir que la version anglaise a un avertissement d'avertissement jaune supplémentaire
This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you need a cryptographically secure value, consider using random_int(), random_bytes(), or openssl_random_pseudo_bytes() instead.
Nombre pseudo-aléatoire
où seed est la graine du nombre aléatoire, et i est le nombre de fois que cette fonction de nombre aléatoire est appelée. Lorsque l’on connaît les deux valeurs de i et rand en même temps, on peut facilement calculer la valeur de seed. Par exemple, rand=21 et i=2 sont remplacés dans la fonction 21=seed+(2*10) pour obtenir seed=1. N'est-ce pas très simple ? Après avoir obtenu la graine, nous pouvons calculer la valeur du rand lorsque i est n'importe quelle valeur. rand = seed+(i*10)
Amorçage automatique de PHP
PHPAPI void php_mt_srand(uint32_t seed) { /* Seed the generator with a simple uint32 */ php_mt_initialize(seed, BG(state)); php_mt_reload(); /* Seed only once */ BG(mt_rand_is_seeded) = 1; } /* }}} */ /* {{{ php_mt_rand */ PHPAPI uint32_t php_mt_rand(void) { /* Pull a 32-bit integer from the generator state Every other access function simply transforms the numbers extracted here */ register uint32_t s1; if (UNEXPECTED(!BG(mt_rand_is_seeded))) { php_mt_srand(GENERATE_SEED()); } if (BG(left) == 0) { php_mt_reload(); } --BG(left); s1 = *BG(next)++; s1 ^= (s1 >> 11); s1 ^= (s1 << 7) & 0x9d2c5680U; s1 ^= (s1 << 15) & 0xefc60000U; return ( s1 ^ (s1 >> 18) ); }
<?php //pid.php echo getmypid();
<?php //test.php $old_pid = file_get_contents('http://localhost/pid.php'); $i=1; while(true){ $i++; $pid = file_get_contents('http://localhost/pid.php'); if($pid!=$old_pid){ echo $i; break; } }
<?php //pid1.php if(isset($_GET['rand'])){ echo mt_rand(); }else{ echo getmypid(); }
<?php //pid2.php echo mt_rand();
<?php //test.php $old_pid = file_get_contents('http://localhost/pid1.php'); echo "old_pid:{$old_pid}\r\n"; while(true){ $pid = file_get_contents('http://localhost/pid1.php'); if($pid!=$old_pid){ echo "new_pid:{$pid}\r\n"; for($i=0;$i<20;$i++){ $random = mt_rand(1,2); echo file_get_contents("http://localhost/pid".$random.".php?rand=1")." "; } break; } }
old_pid:972 new_pid:7752 1513334371 2014450250 1319669412 499559587 117728762 1465174656 1671827592 1703046841 464496438 1974338231 46646067 981271768 1070717272 571887250 922467166 606646473 134605134 857256637 1971727275 2104203195
smldhz@vm:~/php_mt_seed-3.2$ ./php_mt_seed 1513334371 Found 0, trying 704643072 - 738197503, speed 28562751 seeds per second seed = 735487048 Found 1, trying 1308622848 - 1342177279, speed 28824291 seeds per second seed = 1337331453 Found 2, trying 3254779904 - 3288334335, speed 28811010 seeds per second seed = 3283082581 Found 3, trying 4261412864 - 4294967295, speed 28677071 seeds per second Found 3
<?php mt_srand(735487048);//手工播种 for($i=0;$i<21;$i++){ echo mt_rand()." "; }
php_mt_seed
Nous savons déjà que la génération de nombres aléatoires dépend d'une fonction spécifique, qui a été supposée être rand = seed+(i*10)
ci-dessus. Pour une fonction aussi simple, on peut bien sûr calculer directement (oralement) une solution (un groupe), mais la fonction réellement utilisée par mt_rand() est assez complexe et ne peut être inversée. Une méthode de craquage efficace consiste à énumérer de manière exhaustive toutes les graines, à générer une séquence de nombres aléatoires basée sur la graine, puis à la comparer avec une séquence de nombres aléatoires connue pour vérifier si la graine est correcte. php_mt_seed^phpmtseed est un tel outil. Il est très rapide et ne prend que quelques minutes pour exécuter la graine 2^32 bits. Il peut directement exploser les graines possibles en fonction de la sortie d'un seul mt_rand() (exemple ci-dessus). Bien sûr, il peut également exploser les graines qui limitent la sortie MIN MAX comme mt_rand(1,100)
(utile dans les exemples ci-dessous).
Problèmes de sécurité
Cela dit, pourquoi les nombres aléatoires sont-ils dangereux ? En fait, il n'y a rien de mal avec la fonction elle-même, et le responsable indique également clairement que les nombres aléatoires générés ne doivent pas être utilisés à des fins de cryptage de sécurité (bien que le manuel de la version chinoise ne l'écrive pas). Le problème est que le développeur ne réalise pas qu’il ne s’agit pas d’un nombre véritablement aléatoire. Nous savons déjà que des graines peuvent être extraites d'une séquence connue de nombres aléatoires. C'est-à-dire que tant qu'il y a un nombre aléatoire de sortie ou sa valeur dérivée (valeur aléatoire réversible) dans n'importe quelle page, alors le nombre aléatoire dans n'importe quelle autre page ne sera plus un « nombre aléatoire ». Les exemples courants de génération de nombres aléatoires incluent les codes de vérification, les noms de fichiers aléatoires, etc. Des nombres aléatoires courants sont utilisés pour la vérification de la sécurité, comme la récupération des valeurs de vérification du mot de passe, telles que les clés de cryptage, etc. Un scénario d'attaque idéal :
En pleine nuit, en attendant qu'Apache (nginx) reprenne tous les processus PHP (pour s'assurer que la prochaine visite sera ré-amorcée), visitez une fois la page de codes de vérification, inversez le nombre aléatoire en fonction des caractères du code de vérification, puis explosez les graines de nombres aléatoires en fonction de nombres aléatoires. Visitez ensuite la page de récupération de mot de passe, et le lien de récupération de mot de passe généré est basé sur des nombres aléatoires. Nous pouvons facilement calculer ce lien et récupérer le mot de passe de l'administrateur...XXOO
Instance
PHPCMS MT_RAND SEED CRACK mène à la clé d'authentification fuite. Yu Niu écrit mieux que moi, il suffit de lire le sien
La fuite de clé d'authentification Discuz x3.2 est en fait similaire. Le patch officiel a été publié et ceux qui sont intéressés peuvent l'analyser eux-mêmes.
Résumé
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!