Comment sélectionner une valeur aléatoire dans un tableau en PHP. Php random : Comment obtenir une valeur aléatoire à partir d'un tableau Php random value


Les valeurs aléatoires sont partout en PHP. Dans tous les frameworks, dans de nombreuses bibliothèques. Vous avez probablement écrit vous-même une tonne de code qui utilise des valeurs aléatoires pour générer des jetons et des sels, et comme entrée dans des fonctions. De plus, les valeurs aléatoires jouent un rôle important dans la résolution de divers problèmes :

  1. Pour sélectionner au hasard des options dans un pool ou une gamme d’options connues.
  2. Pour générer des vecteurs d'initialisation pour le chiffrement.
  3. Pour générer des jetons imprévisibles ou des valeurs uniques lors de l'autorisation.
  4. Pour générer des identifiants uniques, tels que des identifiants de session.

Dans tous ces cas, il existe une vulnérabilité caractéristique. Si un attaquant devine ou prédit la sortie de votre générateur de nombres aléatoires (RNG) ou de votre générateur de nombres pseudo-aléatoires (PRNG), il pourra calculer les jetons, sels, nonces et vecteurs d'initialisation cryptographiques créés par ce générateur. Il est donc très important de générer des valeurs aléatoires de haute qualité, c’est-à-dire extrêmement difficiles à prédire. Ne rendez jamais prévisibles les jetons de réinitialisation de mot de passe, les jetons CSRF, les clés API, les noms occasionnels ou les jetons d'autorisation !


Il existe deux autres vulnérabilités potentielles associées aux valeurs aléatoires en PHP :

  1. Divulgation d'information.
  2. Entropie insuffisante.

Dans ce contexte, la « divulgation d'informations » fait référence à la fuite de l'état interne d'un générateur de nombres pseudo-aléatoires - sa valeur de départ. Des fuites comme celles-ci peuvent faciliter grandement la prévision des futurs résultats du PRNG.


Le «manque d'entropie» décrit une situation dans laquelle la variabilité de l'état interne initial (graine) d'un PRNG ou de sa sortie est si petite que toute la plage des valeurs possibles est relativement facile à forcer brutalement. Pas une très bonne nouvelle pour les programmeurs PHP.


Nous examinerons les deux vulnérabilités en détail avec des exemples de scénarios d'attaque. Mais d’abord, comprenons ce qu’est réellement une valeur aléatoire lorsqu’il s’agit de programmation PHP.

A quoi servent les valeurs aléatoires ?

La confusion sur le but des variables aléatoires est aggravée par un malentendu général. Vous avez sans doute entendu parler de la différence entre des valeurs aléatoires cryptographiquement fortes et de vagues valeurs "uniques" "pour d'autres utilisations". L'impression principale est que les valeurs aléatoires utilisées en cryptographie nécessitent un caractère aléatoire de haute qualité (ou plus précisément, une entropie élevée), tandis que les valeurs d'autres applications peuvent se débrouiller avec moins d'entropie. Je trouve cette impression fausse et contre-productive. La vraie différence entre les valeurs aléatoires imprévisibles et celles nécessaires à des tâches triviales est que la prévisibilité de ces dernières n'entraîne pas de conséquences néfastes. Cela exclut complètement la cryptographie de toute considération. En d’autres termes, si vous utilisez une valeur aléatoire dans un problème non trivial, vous devez automatiquement choisir des RNG beaucoup plus puissants.


La force des valeurs aléatoires est déterminée par l'entropie dépensée pour les générer. L'entropie est une mesure d'incertitude exprimée en « bits ». Par exemple, si je prends un bit binaire, sa valeur pourrait être 0 ou 1. Si l'attaquant ne connaît pas la valeur exacte, alors nous avons une entropie de 2 bits (c'est-à-dire un tirage au sort). Si l’attaquant sait que la valeur est toujours 1, alors on a une entropie de 0 bit, puisque la prévisibilité est l’antonyme de l’incertitude. De plus, le nombre de bits peut varier de 0 à 2. Par exemple, si 99 % du temps un bit binaire est 1, alors l'entropie peut être légèrement supérieure à 0. Ainsi, plus nous choisissons de bits binaires indéfinis, mieux c'est.


En PHP, cela se voit plus clairement. La fonction mt_rand() génère des valeurs aléatoires, ce sont toujours des nombres. Il n'affiche pas de lettres, de caractères spéciaux ou d'autres significations. Cela signifie que pour chaque octet, l'attaquant a beaucoup moins de suppositions, c'est-à-dire une faible entropie. Si nous remplaçons mt_rand() par la lecture des octets de la source Linux /dev/random , nous obtenons des octets véritablement aléatoires : ils sont générés en fonction du bruit généré par les pilotes de périphériques système et d'autres sources. Évidemment, cette option est bien meilleure car elle fournit beaucoup plus de bits d’entropie.


Le caractère indésirable de mt_rand() est également indiqué par le fait qu'il ne s'agit pas d'un générateur de nombres véritablement aléatoires, mais pseudo-aléatoires, ou, comme on l'appelle aussi, d'un générateur déterministe de séquences binaires aléatoires (Deterministic Random Bit Generator, DRBG ). Il implémente un algorithme appelé Mersenne Twister, qui génère des nombres distribués de telle manière que le résultat soit proche de celui d'un véritable générateur de nombres aléatoires. mt_rand() utilise une seule valeur aléatoire – la graine ; sur cette base, un algorithme fixe génère des valeurs pseudo-aléatoires.


Jetez un œil à cet exemple, vous pouvez le tester vous-même :


mt_srand(1361152757.2); pour ($i=1; $i< 25; $i++) { echo mt_rand(), PHP_EOL; }

Il s'agit d'une simple boucle exécutée après que la fonction vortex PHP Mersenne ait reçu une valeur initiale prédéfinie. Il a été obtenu à partir de la sortie de la fonction donnée en exemple dans la documentation de mt_srand() et en utilisant les secondes et microsecondes actuelles. Si vous exécutez le code ci-dessus, il affichera 25 nombres pseudo-aléatoires. Ils ont l'air aléatoires, pas de coïncidences, tout va bien. Exécutons à nouveau le code. Avez-vous remarqué quelque chose ? A savoir : les MÊMES numéros sont affichés. Exécutons-le pour la troisième, quatrième, cinquième fois. Dans les anciennes versions de PHP, le résultat peut être différent, mais ce n'est pas le problème car il est commun à toutes les versions modernes de PHP.


Si un attaquant obtient la valeur de départ d'un tel PRNG, il pourra alors prédire l'intégralité de la sortie de mt_rand() . La protection de la valeur initiale est donc de la plus haute importance. Si vous le perdez, vous n'avez plus le droit de générer des valeurs aléatoires...


Vous pouvez générer la valeur initiale de deux manières :

  • manuellement, à l'aide de la fonction mt_srand(),
  • vous ignorerez mt_srand() et laisserez PHP le générer automatiquement.

La deuxième option est préférable, mais même aujourd'hui, les applications héritées héritent souvent de l'utilisation de mt_srand(), même après un portage vers des versions plus modernes de PHP.


Cela augmente le risque que l'attaquant récupère la valeur initiale (Seed Recovery Attack), ce qui lui donnera suffisamment d'informations pour prédire les valeurs futures. En conséquence, toute application après une telle fuite devient vulnérable à une attaque de divulgation d’informations. Il s’agit là d’une réelle vulnérabilité, malgré son caractère apparemment passif. La fuite d'informations sur le système local peut aider l'attaquant lors d'attaques ultérieures, qui violeront le principe de défense en profondeur.

Valeurs aléatoires en PHP

PHP utilise trois PRNG, et si un attaquant accède aux graines utilisées dans ses algorithmes, il pourra prédire les résultats de son travail :

  1. Générateur congruentiel linéaire (LCG), lcg_value() .
  2. Vortex de Mersenne, mt_rand() .
  3. Fonction C prise en charge localement rand() .

Ces générateurs sont également utilisés en interne, pour des fonctions comme array_rand() et uniqid() . Cela signifie qu'un attaquant peut prédire le résultat de ces fonctions et d'autres qui utilisent les PRNG internes de PHP s'il obtient toutes les graines requises. Cela signifie également que vous ne pouvez pas améliorer votre défense en confondant l'attaquant avec plusieurs appels aux générateurs. Cela est particulièrement vrai pour les applications open source. Un attaquant est capable de prédire TOUTES les sorties pour toute valeur initiale connue de lui.


Pour améliorer la qualité des valeurs aléatoires générées pour les tâches non triviales, PHP a besoin de sources d'entropie externes fournies par le système d'exploitation. Sous Linux, /dev/urandom est généralement utilisé, vous pouvez le lire directement ou y accéder indirectement en utilisant les fonctions openssl_pseudo_random_bytes() ou mcrypt_create_iv(). Les deux peuvent utiliser un générateur de nombres pseudo-aléatoires cryptographiquement sécurisé (CSPRNG) sous Windows, mais en PHP dans l'espace utilisateur, il n'existe pas encore de méthode directe pour obtenir des données de ce générateur sans les extensions fournies par ces fonctions. En d’autres termes, assurez-vous que la version de PHP de votre serveur a l’extension OpenSSL ou Mcrypt activée.


/dev/urandom est un PRNG, mais obtient souvent de nouvelles graines de la source à haute entropie /dev/random . Cela en fait une cible peu intéressante pour un attaquant. Nous essayons d'éviter de lire directement depuis /dev/random car c'est une ressource bloquante. S'il manque d'entropie, toutes les lectures seront bloquées jusqu'à ce qu'il obtienne à nouveau suffisamment d'entropie de l'environnement système. Bien que pour les tâches les plus importantes, vous devez utiliser /dev/random .


Tout cela nous amène à la règle :


Tous les processus qui impliquent l'utilisation de nombres aléatoires non triviaux DOIVENT utiliser openssl_pseudo_random_bytes(). Alternativement, vous POUVEZ essayer de lire directement les octets de /dev/urandom. Si aucune des deux options ne fonctionne et que vous n'avez pas le choix, vous DEVEZ alors générer la valeur en mélangeant fortement les données provenant de plusieurs sources disponibles de valeurs aléatoires ou secrètes.

Vous trouverez une implémentation de base de cette règle dans la bibliothèque de référence SecurityMultiTool. Comme d'habitude, les internes de PHP préfèrent rendre la vie difficile aux programmeurs plutôt que d'inclure directement des solutions sécurisées dans le noyau PHP.


Assez de théorie, voyons maintenant comment attaquer une application, armé de ce qui précède.

Attaque sur les générateurs de nombres aléatoires en PHP

Pour plusieurs raisons, PHP utilise les PRNG pour résoudre des problèmes non triviaux.


La fonction openssl_pseudo_random_bytes() n'était disponible qu'en PHP 5.3. Sous Windows, cela provoquait des problèmes de blocage jusqu'à la sortie de la version 5.3.4. Également dans PHP 5.3, la fonction mcrypt_create_iv() sous Windows a commencé à prendre en charge la source MCRYPT_DEV_URANDOM. Auparavant, Windows ne prenait en charge que MCRYPT_RAND – essentiellement le même système PRNG utilisé en interne par la fonction rand(). Comme vous pouvez le constater, avant PHP 5.3, il y avait de nombreuses lacunes, de sorte que de nombreuses applications héritées écrites dans les versions précédentes n'étaient peut-être pas passées à des PRNG plus puissants.


Le choix des extensions Openssl et Mcrypt est à votre discrétion. Comme on ne peut pas compter sur leur disponibilité même sur les serveurs exécutant PHP 5.3, les applications utilisent souvent les PRNG intégrés à PHP comme solution de secours pour générer des valeurs aléatoires non triviales.


Mais dans les deux cas, nous avons des problèmes non triviaux qui utilisent des valeurs aléatoires générées par des PRNG avec des graines à faible entropie. Cela nous rend vulnérables aux attaques de récupération. Regardons un exemple simple.


Imaginons que nous trouvions une application en ligne qui utilise le code suivant pour générer des jetons utilisés dans diverses tâches au sein de l'application :


$token = hash("sha512", mt_rand());

Il existe des moyens plus complexes de générer des jetons, mais c'est une bonne option. Il n'y a qu'un seul appel à mt_rand(), haché avec SHA512. En pratique, si un programmeur décide que les fonctions de valeurs aléatoires de PHP sont « suffisamment aléatoires », alors il choisira très probablement l'approche simpliste jusqu'à ce que le mot « cryptographie » soit mentionné. Par exemple, les cas non cryptographiques incluent les jetons d'accès, les jetons CSRF, les valeurs uniques d'API et les jetons de réinitialisation de mot de passe. Avant de continuer, je vais détailler toute l'étendue de la vulnérabilité de cette application afin que vous compreniez mieux ce qui rend les applications vulnérables en premier lieu.

Caractéristiques de l'application vulnérable

Ce n'est pas une liste exhaustive. En pratique, la liste des caractéristiques peut différer !

1. Le serveur utilise mod_php, qui, lorsqu'il est utilisé avec KeepAlive, permet à plusieurs requêtes d'être traitées par le même processus PHP.

Ceci est important car les générateurs de nombres aléatoires en PHP ne sont générés qu'une seule fois par processus. Si nous pouvons faire deux requêtes ou plus au processus, alors il utilisera la même valeur initiale. L'essence de l'attaque est d'utiliser l'expansion d'un jeton pour extraire la valeur de départ, qui est nécessaire pour prédire un autre jeton généré sur la base de la MÊME valeur de départ (c'est-à-dire dans le même processus). Puisque mod_php est idéal pour utiliser plusieurs requêtes pour récupérer des valeurs aléatoires associées, il peut parfois être possible de récupérer plusieurs valeurs liées à mt_rand() avec une seule requête. Cela rend toute exigence de mod_php redondante. Par exemple, une partie de l'entropie utilisée pour générer la graine pour mt_rand() peut s'échapper via les ID de session ou les valeurs de sortie dans la même requête.

2. Le serveur révèle les jetons CSRF, les jetons de réinitialisation de mot de passe ou les jetons de confirmation de compte générés sur la base des jetons mt_rand()

Pour extraire la valeur de départ, nous devons vérifier directement le nombre généré par les générateurs en PHP. Et peu importe la manière dont il est utilisé. Nous pouvons l'extraire de n'importe quelle valeur disponible, que ce soit la sortie de mt_rand(), un CSRF haché ou un jeton de vérification de compte. Même les sources indirectes conviennent, dans lesquelles une valeur aléatoire détermine un comportement différent en sortie, qui révèle cette valeur même. La principale limitation est qu’il doit provenir du même processus qui génère le deuxième jeton que nous essayons de prédire. Et il s’agit d’une vulnérabilité de « divulgation d’informations ». Comme nous le verrons bientôt, une fuite de sortie PRNG peut être extrêmement dangereuse. Notez que la vulnérabilité n'est pas limitée à une seule application : vous pouvez lire la sortie PRNG dans une application sur le serveur et l'utiliser pour déterminer la sortie dans une autre application sur le même serveur, à condition qu'elles utilisent toutes deux le même processus PHP.

3. Algorithme de génération de jetons faible connu

Vous pouvez le calculer :

  • après avoir fouillé dans les sources de l'application open source,
  • soudoyer un employé ayant accès à un code source personnel,
  • retrouver un ancien salarié qui nourrit une rancune contre son ancien employeur,
  • ou simplement deviner quel algorithme il pourrait y avoir.

Certaines méthodes de génération de jetons sont plus évidentes, d’autres sont plus populaires. Une génération vraiment faible signifie utiliser l'un des générateurs de nombres aléatoires de PHP (par exemple mt_rand()), une entropie faible (pas d'autres sources de données non définies) et/ou un hachage faible (par exemple MD5 ou pas de hachage du tout). L'exemple de code discuté ci-dessus présente les caractéristiques d'une méthode de génération faible. J'ai également utilisé le hachage SHA512 pour démontrer que le masquage est toujours une solution insatisfaisante. SHA512 est un hachage faible car il est rapide à calculer, ce qui signifie qu'un attaquant peut forcer brutalement les données d'entrée sur n'importe quel CPU ou GPU à une vitesse incroyable. Et n’oubliez pas que la loi de Moore est également toujours en vigueur, ce qui signifie que la vitesse de force brute augmentera à chaque nouvelle génération de CPU/GPU. Par conséquent, les mots de passe doivent être hachés à l'aide d'outils dont le déchiffrement prend un certain temps, quelles que soient les performances du processeur ou la loi de Moore.

Effectuer une attaque

Notre attaque est assez simple. Dans le cadre de la connexion à un processus PHP, nous organiserons une session rapide et enverrons deux requêtes HTTP distinctes (requête A et requête B). La session sera maintenue par le serveur jusqu'à ce que la deuxième demande soit reçue. La requête A vise à obtenir un jeton disponible comme CSRF, un jeton de réinitialisation de mot de passe (envoyé à l'attaquant par courrier) ou quelque chose de similaire. N'oubliez pas les autres fonctionnalités telles que le balisage en ligne utilisé dans les demandes d'identifiants arbitraires, etc. Nous tourmenterons le jeton d'origine jusqu'à ce qu'il nous donne sa valeur initiale. Tout cela fait partie d'une attaque de récupération de graine : où la graine a si peu d'entropie qu'elle peut être forcée brutalement ou recherchée dans une table arc-en-ciel précalculée.


La requête B résoudra un problème plus intéressant. Faisons une demande de réinitialisation du mot de passe de l'administrateur local. Cela déclenchera la génération d'un jeton (en utilisant un nombre aléatoire basé sur la même graine que celle que nous extrayons avec la requête A si les deux requêtes sont envoyées avec succès au même processus PHP). Ce token sera stocké dans la base de données en prévision du moment où l'administrateur utilisera le lien de réinitialisation du mot de passe qui lui sera envoyé par email. Si nous pouvons extraire la valeur de départ du jeton de la requête A, alors sachant comment le jeton de la requête B est généré, nous pouvons prédire le jeton de réinitialisation du mot de passe. Cela signifie que nous pouvons suivre le lien de réinitialisation avant que l'administrateur ne lise la lettre !


Voici la séquence des événements :

  1. À l’aide de la requête A, nous obtenons le jeton et le procédons à une ingénierie inverse pour calculer la valeur initiale.
  2. En utilisant la requête B, nous obtenons un jeton généré sur la base de la même valeur initiale. Ce jeton est stocké dans la base de données de l'application pour une future réinitialisation du mot de passe.
  3. Nous cassons le hachage SHA512 pour obtenir le nombre aléatoire généré par le serveur.
  4. En utilisant la valeur aléatoire résultante, nous forçons brutalement la valeur initiale générée avec son aide.
  5. Nous utilisons la graine pour calculer une série de valeurs aléatoires qui peuvent probablement constituer la base d'un jeton de réinitialisation de mot de passe.
  6. Nous utilisons ce(s) jeton(s) pour réinitialiser le mot de passe administrateur.
  7. Nous accédons au compte administrateur, nous amusons et bénéficions. Eh bien, au moins, nous nous amusons.

Commençons à pirater...

Piratage d'application étape par étape

Étape 1. Faites la demande A pour récupérer le jeton

Nous supposons que le jeton cible et le jeton de réinitialisation du mot de passe dépendent de la sortie de mt_rand() . Il faut donc le choisir. Dans l'application de notre scénario imaginaire, tous les jetons sont générés de la même manière, nous pouvons donc simplement extraire le jeton CSRF et le sauvegarder pour plus tard.

Étape 2. Effectuez la demande B pour recevoir le jeton de réinitialisation du mot de passe généré pour le compte administrateur

Cette demande consiste en la simple soumission d'un formulaire de réinitialisation de mot de passe. Le token sera enregistré dans la base de données et envoyé à l'utilisateur par mail. Nous devons calculer correctement ce jeton. Si les spécifications du serveur sont exactes, alors la requête B utilise le même processus PHP que la requête A. Par conséquent, les appels à mt_rand() utiliseront la même valeur initiale dans les deux cas. Vous pouvez même utiliser la requête A pour capturer le jeton CSRF du formulaire de réinitialisation afin de permettre la soumission dans le but de rationaliser la procédure (en évitant l'aller-retour intermédiaire).

Étape 3. Piratez le hachage SHA512 du jeton reçu de la requête A

SHA512 inspire l'admiration des programmeurs : il possède le plus grand nombre de toute la famille d'algorithmes SHA-2. Cependant, il y a un problème avec la méthode de génération de jetons de notre victime : les valeurs aléatoires sont limitées uniquement aux nombres (c'est-à-dire que le degré d'incertitude, ou d'entropie, est négligeable). Si vous vérifiez la sortie de mt_getrandmax() , vous constaterez que le plus grand nombre aléatoire que mt_rand() peut générer est de 2,147 milliards et quelques changements. Ce nombre limité de fonctionnalités rend SHA512 vulnérable à la force brute.


Ne me croyez pas sur parole. Si vous possédez une carte vidéo discrète de l'une des dernières générations, vous pouvez procéder comme suit. Puisque nous recherchons un seul hachage, j'ai décidé d'utiliser un merveilleux outil de force brute - hashcat-lite. Il s'agit de l'une des versions les plus rapides de hashcat et elle est disponible pour tous les principaux systèmes d'exploitation, y compris Windows.


Utilisez ce code pour générer un jeton :


$rand = mt_rand(); echo "Nombre aléatoire : ", $rand, PHP_EOL ; $jeton = hash("sha512", $rand); echo "Jeton : ", $jeton, PHP_EOL ;

Ce code reproduit le jeton de la requête A (il contient le nombre aléatoire dont nous avons besoin et est caché dans le hachage SHA512) et l'exécute via hashcat :


./oclHashcat-lite64 -m1700 --pw-min=1 --pw-max=10 -1?d -o ./seed.txt ?d?d?d?d?d?d?d?d?d?d

Voici ce que signifient toutes ces options :

  • -m1700 : Spécifie l'algorithme de hachage, où 1700 signifie SHA512.
  • --pw-min=1 : définit la longueur d'entrée minimale de la valeur hachée.
  • --pw-max=10 : définit la longueur d'entrée maximale de la valeur hachée (10 pour mt_rand()).
  • -1?d : spécifie que nous avons besoin d'un dictionnaire personnalisé contenant uniquement des nombres (c'est-à-dire 0-9).
  • -o ./seed.txt : fichier pour écrire les résultats. Rien ne s'affiche à l'écran, alors n'oubliez pas de paramétrer cette option !
  • ?d?d?d?d?d?d?d?d?d?d : masque qui précise le format à utiliser (tous les chiffres jusqu'à un maximum de 10).

Si tout fonctionne correctement et que votre GPU ne fond pas, Hashcat calculera le nombre aléatoire haché en quelques minutes. Oui, des minutes. J'ai déjà expliqué comment fonctionne l'entropie. Voir par vous-même. La fonction mt_rand() a si peu de capacités que les hachages SHA512 de toutes les valeurs peuvent en fait être calculés en très peu de temps. Il ne servait donc à rien de hacher la sortie de mt_rand() .

Étape 4. Restaurez la valeur initiale en utilisant un nombre aléatoire fraîchement piraté

Comme nous l'avons vu ci-dessus, quelques minutes suffisent pour extraire toute valeur générée par mt_rand() de SHA512. Armés d'une valeur aléatoire, nous pouvons exécuter un autre outil de force brute - php_mt_seed. Ce petit utilitaire prend la sortie de mt_rand() et, après force brute, calcule la valeur initiale à partir de laquelle l'analyse aurait pu être générée. Téléchargez la version actuelle, compilez et exécutez. Si vous rencontrez des problèmes de compilation, essayez une ancienne version (j'ai eu des problèmes avec les environnements virtuels avec les nouvelles).


./php_mt_seed

Cela peut prendre un peu plus de temps que le craquage SHA512 car il est effectué sur le processeur. Sur un processeur décent, l'utilitaire trouvera toute la plage possible de la valeur initiale en quelques minutes. Le résultat est une ou plusieurs valeurs possibles (c'est-à-dire les valeurs qui auraient pu être utilisées pour produire le nombre aléatoire). Encore une fois, nous constatons le résultat d'une faible entropie, mais cette fois en relation avec la génération par PHP des valeurs initiales pour la fonction vortex de Mersenne. Nous verrons plus tard comment ces valeurs ont été générées, vous comprendrez donc pourquoi la force brute peut être appliquée si rapidement.


Donc, avant cela, nous utilisions des outils de piratage simples disponibles sur le Web. Ils sont orientés vers les appels mt_rand(), mais illustrent une idée qui peut être appliquée à d'autres scénarios (par exemple, des appels séquentiels mt_rand() lors de la génération de jetons). Gardez également à l’esprit que la vitesse de piratage n’empêche pas la génération de tables arc-en-ciel prenant en compte des approches spécifiques de génération de jetons. Voici un autre outil qui exploite les vulnérabilités mt_rand() et est écrit en Python.

Étape 5. Générer d'éventuels jetons de réinitialisation du mot de passe du compte administrateur

Supposons que dans les requêtes A et B, seules deux requêtes ont été adressées à mt_rand() . Commençons maintenant à prédire les jetons en utilisant les valeurs initiales possibles calculées précédemment :


function prédire($seed) ( /** * Passer la valeur initiale à PRNG */ mt_srand($seed); /** * Ignorer l'appel de fonction de la requête A */ mt_rand(); /** * Prédire et renvoyer le celui généré dans la requête B token */ $token = hash("sha512", mt_rand()); return $token; )

Cette fonction prédit un jeton de réinitialisation pour chaque graine possible.

Étapes 6 et 7 : réinitialisez le mot de passe de votre compte administrateur et amusez-vous !

Vous devez maintenant collecter une URL contenant un jeton qui vous permettra de réinitialiser le mot de passe administrateur en raison de la vulnérabilité de l'application et d'accéder à votre compte. Vous découvrirez peut-être que vous pouvez publier du HTML non filtré sur un forum ou dans un article (une violation courante du principe de défense en profondeur). Cela vous permettra d'effectuer une attaque XSS étendue sur tous les autres utilisateurs de l'application, infectant leurs ordinateurs avec des logiciels malveillants et une surveillance Man-In-The-Browser. Sérieusement, pourquoi s’arrêter simplement à l’accès ? Le but de ces vulnérabilités apparemment passives et peu dangereuses est d’aider l’attaquant à pénétrer lentement là où il peut enfin atteindre son objectif principal. Le piratage, c'est comme jouer à un jeu de combat d'arcade où vous devez appuyer rapidement sur la bonne combinaison pour déclencher une série d'attaques puissantes.

Analyse post-attaque

Le scénario ci-dessus et la simplicité des étapes devraient vous démontrer clairement les dangers de mt_rand() . Les risques sont si évidents que nous pouvons désormais considérer toute valeur de sortie mt_rand() faiblement cachée, accessible à un attaquant sous quelque forme que ce soit, comme une vulnérabilité de « divulgation d'informations ».


De plus, il y a une deuxième facette de cette histoire. Par exemple, si vous dépendez d'une bibliothèque qui utilise innocemment mt_rand() pour certaines tâches importantes, même sans divulguer les valeurs résultantes, alors en utilisant un jeton « qui fuit » pour vos besoins, vous compromettrez cette bibliothèque. Et c'est un problème car la bibliothèque ou le framework ne fait rien pour atténuer l'attaque de restauration de la valeur initiale. Devrions-nous blâmer l'utilisateur pour la fuite des valeurs mt_rand() - ou la bibliothèque pour ne pas avoir appliqué de meilleures valeurs aléatoires ?


En fait, les deux sont plutôt coupables. La bibliothèque ne doit pas choisir mt_rand() (ou toute autre source unique de faible entropie) pour des problèmes importants comme seule source de valeurs aléatoires. Et l'utilisateur ne doit pas écrire de code qui divulgue les valeurs mt_rand(). Alors oui, vous pouvez commencer à pointer du doigt des exemples analphabètes d’utilisation de mt_rand() , même si cela n’entraîne pas de fuites directes.


Il n’y a pas que les vulnérabilités liées à la divulgation d’informations dont vous devez vous soucier. Il est également important d’être conscient du manque de vulnérabilités entropiques, qui rendent les applications vulnérables à la force brute des jetons, clés ou noms occasionnels sensibles qui ne sont pas techniquement cryptographiques, mais sont utilisés dans le fonctionnement de fonctions d’application non triviales.

Et maintenant tout est pareil

Nous savons maintenant que l'utilisation de PRNG intégrés à PHP est considérée comme un manque de vulnérabilité entropique (c'est-à-dire que la réduction de l'incertitude facilite la force brute). Nous pouvons étendre notre attaque :


Une vulnérabilité de divulgation d’informations rend cette méthode de génération de jetons totalement inutile. Pour comprendre pourquoi, regardons de plus près la fonction PHP uniqid() . Sa définition :


Sur la base de l'heure actuelle en microsecondes, obtient un identifiant de préfixe unique.


Comme vous vous en souvenez, l'entropie est une mesure d'incertitude. En raison d'une vulnérabilité de divulgation d'informations, les valeurs générées par mt_rand() peuvent être divulguées, donc l'utilisation de mt_rand() comme préfixe d'identifiant unique n'ajoute aucune incertitude. Dans notre exemple, le seul autre type d’entrée dans uniqid() est le temps. Mais ce n’est certainement PAS vague. Cela change de manière linéaire et prévisible. Et les valeurs prévisibles ont une entropie extrêmement faible.


Bien entendu, la définition fait référence aux « microsecondes », c’est-à-dire aux millionièmes de seconde. Cela nous donne 1 000 000 de nombres possibles. Ici, j'ignore les valeurs supérieures à 1 seconde car leur fraction et leur mesurabilité sont si grandes (par exemple, l'en-tête HTTP Date dans une réponse) que cela ne donne presque rien. Avant d'entrer dans les détails, décortiquons la fonction uniqid() et regardons son code C :


gettimeofday((struct timeval *) &tv, (struct timezone *) NULL); sec = (int) tv.tv_sec; usec = (int) (tv.tv_usec % 0x100000); /* usec peut avoir une valeur maximale de 0xF423F, nous utilisons donc * usecs uniquement cinq nombres hexadécimaux. */ if (more_entropy) ( spprintf(&uniqid, 0, "%s%08x%05x%.8F", préfixe, sec, usec, php_combined_lcg(TSRMLS_C) * 10); ) else ( spprintf(&uniqid, 0, "% s%08x%05x", préfixe, sec, usec); ) RETURN_STRING(uniqid, 0);

Si cela vous semble trop compliqué, vous pouvez tout répliquer dans le bon vieux PHP :


function unique_id($prefix = "", $more_entropy = false) ( list($usec, $sec) = éclater(" ", microtime()); $usec *= 1000000; if(true === $more_entropy) ( return sprintf("%s%08x%05x%.8F", $prefix, $sec, $usec, lcg_value()*10); ) else ( return sprintf("%s%08x%05x", $prefix, $ sec, $usec); ) )

Ce code nous indique que le simple fait d'appeler uniqid() sans paramètre nous renverra une chaîne de 13 caractères. Les 8 premiers caractères sont l'horodatage Unix actuel (en secondes), exprimé en hexadécimal. Les 5 derniers caractères sont des microsecondes supplémentaires en hexadécimal. En d’autres termes, la fonction de base uniqid() fournit une mesure très précise du temps système, qui peut être extraite d’un simple appel à uniqid() avec un code comme celui-ci :


$id = uniqid(); $time = str_split($id, 8); $sec = hexdec("0x" . $time); $usec = hexdec("0x" . $time); echo "Secondes : ", $sec, PHP_EOL, "Microsecondes : ", $usec, PHP_EOL ;

Regardez le code C. L'heure exacte du système n'est jamais masquée dans la sortie, quels que soient les paramètres :


echo uniqid(), PHP_EOL; // 514ee7f81c4b8 echo uniqid("préfixe-"), PHP_EOL; // prefix-514ee7f81c746 echo uniqid("prefix-", true), PHP_EOL; // préfixe-514ee7f81c8993.39593322

Identifiants uniques par force brute

Après réflexion, il devient évident que révéler une valeur uniqid() à un attaquant est un autre exemple de vulnérabilité potentielle de divulgation d'informations. Cela divulgue une heure système très précise, qui peut être utilisée pour prédire l'entrée des appels uniqid() ultérieurs. Cela permet de résoudre tous les dilemmes qui surviennent lorsque l’on tente de prédire les microsecondes en réduisant les 1 000 000 de possibilités à une plage plus étroite. Puisque cette fuite aurait pu être évoquée plus tard, elle n’est techniquement pas nécessaire dans notre exemple. Regardons à nouveau le code du jeton uniqid() d'origine :


$token = hash("sha512", uniqid(mt_rand()));

À partir de cet exemple, nous pouvons voir qu'en effectuant une attaque de réinitialisation sur mt_rand() combinée à la divulgation d'informations de uniqid() , nous calculerons un ensemble relativement petit de hachages SHA512, qui peuvent s'avérer être des réinitialisations de mot de passe ou d'autres jetons importants. Si vous avez besoin d'une plage étroite d'horodatages sans exploiter la fuite de temps système provenant d'uniqid() , analysons les réponses du serveur, qui contiennent généralement un en-tête HTTP Date. De là, vous pouvez obtenir les horodatages exacts du serveur. Et comme dans ce cas l’entropie est égale à un million de valeurs possibles en microsecondes, vous pouvez la forcer brutalement en quelques secondes !


L’augmentation de l’entropie nous sauvera-t-elle ?

Bien entendu, il est possible d'ajouter de l'entropie à uniqid() en définissant le deuxième paramètre de la fonction sur TRUE :


Comme le montre le code C, la nouvelle source d'entropie utilise la sortie de la fonction interne php_combined_lcg(). Cette fonction est exposée à l'espace utilisateur via la fonction lcg_value(), que j'ai utilisée dans ma conversion PHP de la fonction uniqid(). Essentiellement, il combine deux valeurs générées par deux générateurs linéaires congrus étant donné des valeurs initiales distinctes. Vous trouverez ci-dessous le code qui a fourni aux générateurs ces valeurs initiales. Comme pour mt_rand() , ils sont générés une fois par processus PHP et réutilisés dans tous les appels suivants.


static void lcg_seed(TSRMLS_D) /* ((( */ ( struct timeval tv; if (gettimeofday(&tv, NULL) == 0) ( LCG(s1) = tv.tv_sec ^ (tv.tv_usec<<11); } else { LCG(s1) = 1; } #ifdef ZTS LCG(s2) = (long) tsrm_thread_id(); #else LCG(s2) = (long) getpid(); #endif /* Add entropy to s2 by calling gettimeofday() again */ if (gettimeofday(&tv, NULL) == 0) { LCG(s2) ^= (tv.tv_usec<<11); } LCG(seeded) = 1; }

Si vous le regardez trop longtemps et que vous souhaitez lancer quelque chose sur le moniteur, il vaut mieux ne pas le faire. Les moniteurs sont chers de nos jours.


Les deux valeurs initiales utilisent la fonction C gettimeofday() pour capturer l'heure actuelle en secondes et microsecondes depuis l'époque Unix (en référence à l'horloge du serveur). Il convient de noter que les deux appels sont implémentés dans le code source, donc la valeur du compteur microseconde() entre eux sera minime, ce qui réduit l'incertitude introduite. La deuxième valeur initiale sera également mélangée à l'ID du processus en cours, qui dans la plupart des cas sous Linux ne dépassera pas 32 768. Bien sûr, vous pouvez augmenter manuellement la limite à environ 4 millions en modifiant /proc/sys/kernel/pid_max , mais c'est très indésirable.


Il s’avère que la principale source d’entropie utilisée par ces LCG est la microseconde. Par exemple, rappelez-vous notre valeur initiale mt_rand() ? Devinez comment c'est calculé.


#ifdef PHP_WIN32 #define GENERATE_SEED() (((long) (time(0) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C)))) #else #define GENERATE_SEED() (((long ) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C)))) #endif

Cela signifie que toutes les valeurs initiales utilisées en PHP sont interdépendantes. Même les mêmes données d'entrée sont mélangées plusieurs fois. Peut-être pourriez-vous limiter la plage de microsecondes initiales comme nous l'avons vu ci-dessus : en utilisant deux requêtes, la première sautant entre les secondes (le microtime serait donc 0 + le temps d'exécution du prochain appel C gettimeofday()). Vous pouvez même calculer le delta en microsecondes entre d'autres appels gettimeofday() si vous avez accès au code source (la nature open source de PHP aide). Sans oublier que le forçage brutal de la valeur de départ mt_rand() vous donne une valeur de départ finale qui permet une vérification hors ligne.


Cependant, le principal problème réside dans php_combined_lcg() . Il s'agit d'une implémentation de bas niveau dans l'espace utilisateur de la fonction lcg_value() qui obtient la valeur initiale une fois par processus PHP. Et si vous connaissez cette valeur, vous pouvez alors prédire le résultat. Si vous cassez cette noix, alors c'est tout, le jeu est terminé.

Il y a une application pour ça...

J'ai passé beaucoup de temps à me concentrer sur des choses pratiques, alors revenons-y à nouveau. Il n'est pas si facile d'obtenir les deux valeurs initiales utilisées par php_combined_lcg() - il n'est peut-être pas possible de créer une fuite directe. La fonction lcg_value() est relativement peu connue et les programmeurs s'appuient plus souvent sur mt_rand() lorsqu'ils ont besoin du PRNG intégré à PHP. Je ne veux pas empêcher lcg_value() de divulguer la valeur, mais c'est une fonction impopulaire. La paire de LCG combinés ne reflète pas non plus la fonction d'amorçage (vous ne pouvez donc pas simplement rechercher des appels à mt_srand() pour identifier un mécanisme d'amorçage qui fuit hérité du code hérité de quelqu'un). Cependant, il existe une source fiable qui fournit directement des données pour les graines de force brute : les identifiants de session en PHP.


spprintf(&buf, 0, "%.15s%ld%ld%0.8F", remote_addr ? remote_addr: "", tv.tv_sec, (long int)tv.tv_usec, php_combined_lcg(TSRMLS_C) * 10);

Ce code génère une valeur de pré-hachage pour l'ID de session en utilisant l'IP, l'horodatage, les microsecondes et... la sortie php_combined_lcg(). Compte tenu de la réduction significative du nombre de possibilités micro-temporelles (ce code a besoin de 1 pour générer l'ID et de 2 pour php_combined_lcg() , ce qui entraîne une différence minime entre elles), nous pouvons désormais le forcer brutalement. Nous allons probablement.


Comme vous vous en souvenez peut-être, PHP prend désormais en charge de nouvelles options de session telles que session.entropy_file et session.entropy_length. Ceci est fait pour éviter les ID de session par force brute, au cours desquels vous pouvez rapidement (cela ne prendra pas des heures) obtenir deux valeurs initiales pour les générateurs LCG combinées à l'aide de php_combined_lcg(). Si vous utilisez PHP 5.3 ou une version antérieure, vous avez peut-être mal configuré ces options. Cela signifie qu'il existe une autre vulnérabilité de divulgation d'informations utile qui vous permet de forcer brutalement les ID de session afin d'obtenir les valeurs initiales du LCG.


Pour de tels cas, il existe une application Windows qui vous permet de calculer les valeurs LCG.


À propos, connaître les états LCG vous permet de comprendre comment mt_rand() obtient la valeur initiale, c'est donc une autre façon de contourner le manque de fuites de valeur mt_rand().


Qu'est-ce que tout cela signifie en termes d'ajout d'entropie aux valeurs de retour d'uniqid() ?


$token = hash("sha512", uniqid(mt_rand(), true));

Ceci est un autre exemple de la vulnérabilité potentielle du manque d’entropie. Vous ne pouvez pas compter sur l'entropie avec des fuites (même si vous n'en êtes pas responsable !). Grâce à la fuite d'informations sur l'ID de session, un attaquant peut également prédire la valeur d'entropie qui a été ajoutée à cet ID.


Encore une fois, à qui la faute ? Si l'application X s'appuie sur uniqid() , mais qu'un utilisateur ou une autre application sur le même serveur divulgue l'état LCG interne, vous devez alors prendre des mesures dans les deux situations. Les utilisateurs doivent s'assurer que les identifiants de session utilisent une entropie suffisamment élevée, et les programmeurs tiers doivent comprendre que leurs méthodes de génération de valeurs aléatoires manquent d'entropie, ils doivent donc passer à des alternatives plus appropriées (même si seules des sources d'entropie faibles sont disponibles !) .

À la recherche de l'entropie

PHP à lui seul n'est pas capable de générer une forte entropie. Il n'existe même pas d'API de base pour transférer les données des générateurs PRNG au niveau du système d'exploitation, qui sont des sources fiables d'entropie forte. Par conséquent, vous devez vous fier aux extensions facultatives openssl et mcrypt. Ils offrent des fonctionnalités bien meilleures que leurs cousins ​​​​qui fuient, sont prévisibles et à faible entropie.


Malheureusement, comme les deux extensions sont facultatives, dans certains cas, nous n’avons d’autre choix que de nous fier à des sources d’entropie faibles en dernier recours. Lorsque cela se produit, la faible entropie de mt_rand() doit être complétée par des sources d'incertitude supplémentaires, en mélangeant leurs données dans un seul pool à partir duquel des octets pseudo-aléatoires peuvent être extraits. Un générateur aléatoire similaire utilisant un puissant mélangeur à entropie a déjà été implémenté par Anthony Ferrara dans sa bibliothèque RandomLib. C'est ce que les programmeurs devraient faire autant que possible.


Évitez la tentation de cacher la faiblesse de votre entropie en hachant des transformations mathématiques complexes. L'attaquant répétera tout cela dès qu'il découvrira la valeur initiale primaire. De telles astuces n'augmenteront que légèrement la quantité de calculs lors de la force brute. N'oubliez pas : plus l'entropie est faible, moins il y a d'incertitude ; Moins il y a d’incertitude, moins il faudra forcer les opportunités. La seule solution justifiable est d'augmenter le pool d'entropie que vous utilisez par tous les moyens disponibles.


La bibliothèque RandomLib génère des octets aléatoires en mélangeant des données provenant de différentes sources d'entropie et en localisant les informations dont un attaquant pourrait avoir besoin pour deviner. Par exemple, vous pouvez mélanger les sorties de mt_rand(), uniqid() et lcg_value(), ajouter du PID, de la consommation mémoire, d'autres mesures microtimes, la sérialisation $_ENV, posix_times(), etc. Ou aller encore plus loin, cela permet à RandomLib extensibilité. Disons que nous utilisons des deltas en microsecondes (c'est-à-dire mesurer le nombre de microsecondes dont une fonction a besoin pour fonctionner avec des données d'entrée pseudo-aléatoires comme les appels hash()).

Ajouter des balises

rand(1,N) mais en excluant array(a,b,c,..)

existe-t-il déjà une fonction intégrée que je ne connais pas ou dois-je l'implémenter moi-même (comment ?) ?

MISE À JOUR

Une solution qualifiée doit avoir de l’or, quelle que soit la taille du tableau exclu.

Il n'y a pas de fonction intégrée, mais vous tu peux fais-le:

Function randWithout($from, $to, array $exceptions) ( sort($exceptions); // nous permet d'utiliser break; dans le foreach de manière fiable $number = rand($from, $to - count($exceptions)); / / ou mt_rand() foreach ($exceptions comme $exception) ( if ($number >= $exception) ( $number++; // comble l'écart) else /*if ($number< $exception)*/ { break; } } return $number; }

Ce n'est pas dans ma tête, donc cela pourrait utiliser un polissage - mais au moins vous ne pouvez pas vous retrouver dans un scénario de boucle infinie, même hypothétiquement.

Note: La fonction s'arrête si $exceptions échappements votre plage - par exemple appeler randWithout(1, 2, array(1,2)) ou randWithout(1, 2, array(0,1,2,3)) ne donnera rien de raisonnable (évidemment), mais dans ce cas le numéro renvoyé sera en dehors de la plage $from – $to, il est donc facile à attraper.

S'il est garanti que $exceptions est déjà trié, sort($exceptions); peut être supprimé.

Un régal pour les yeux: Une visualisation quelque peu minimale de l'algorithme.

Je ne pense pas qu'il existe une telle fonction intégrée ; vous devrez probablement le coder vous-même.

Pour coder cela, vous avez deux solutions :

  • Utilisez une boucle pour appeler rand() ou mt_rand() jusqu'à ce qu'elle renvoie la valeur correcte
    • ce qui signifie appeler rand() plusieurs fois, dans le pire des cas
    • mais cela devrait fonctionner correctement si N est grand et que vous n'avez pas beaucoup de valeurs interdites.
  • Créer un tableau contenant uniquement des valeurs légales
    • Et utilise tableau_rand pour en sélectionner une valeur
    • ce qui fonctionnera bien si N est petit

Selon vos besoins et pourquoi, cette approche pourrait être une alternative intéressante.

$numbers = array_diff(range(1, N), array(a, b, c)); // Soit (pas une vraie réponse, mais cela pourrait être utile, selon votre situation) shuffle($numbers); // $numbers est maintenant un tableau trié aléatoirement contenant tous les nombres qui vous intéressent // Ou : $x = $numbers; // $x est maintenant un nombre aléatoire sélectionné parmi l'ensemble de nombres qui vous intéressent

Donc, si vous n'avez pas besoin de générer un ensemble de nombres potentiels à chaque fois, mais de générer un ensemble une fois, puis de sélectionner un groupe de nombres aléatoires dans le même ensemble, cela pourrait être une bonne solution.

Le moyen le plus simple…

Vous devez calculer un tableau d'emplacements manquants afin de pouvoir choisir une position aléatoire dans un tableau contigu de longueur M = N - # d'exceptions et le mapper facilement au tableau d'origine avec des trous. Cela nécessitera un temps et un espace égaux au tableau transmis. Je ne connais pas php depuis un trou dans le sol, alors pardonnez l'exemple de code de texte semi-psudo.

  1. Créez un nouveau tableau Offset de la même longueur que le tableau Exceptions.
  2. in Offset[i] stockera le premier index dans un tableau imaginaire non vide, qui manquerait i éléments dans le tableau d'origine.
  3. Sélectionnez maintenant un élément aléatoire. Choisissez un nombre aléatoire, r , jusqu'à 0..M le nombre d'éléments restants.
  4. Trouvez-moi ce décalage[i]<= r < Offest это легко с бинарным поиском
  5. Retour r+i

Maintenant, ce n'est qu'un croquis, vous devrez vous occuper des extrémités des tableaux, et si quelque chose est indexé sous la forme de 0 ou 1 et tout ce jazz. Si vous êtes intelligent, vous pouvez réellement calculer le tableau Offset à la volée à partir de l'original, mais c'est un peu moins clair.

Peut-être trop tard pour une réponse, mais j'ai trouvé ce morceau de code quelque part dans mon esprit en essayant d'obtenir des données aléatoires d'une base de données basée sur un identifiant aléatoire, à l'exception d'un nombre.

$exclusDonnées = tableau(); // Ceci est votre numéro exclu $maxVal = $this->db->count_all_results("game_pertanyaan"); // Obtenez le nombre maximum basé sur ma base de données $randomNum = rand(1, $maxVal); // Faites la première initiation, je pense que vous pouvez mettre cela directement dans le paramètre while > in_array, cela semble fonctionner aussi, c'est à vous de décider while (in_array ($ randomNum, $ exclusData)) ( $ randomNum = rand (1, $maxVal); ) $randomNum; //Votre nombre aléatoire à l'exclusion d'un nombre que vous choisissez

On m'a déjà demandé plusieurs fois comment j'allais sortie aléatoire de citations sur mon site internet dans le bloc " Citations intelligentes". Ensuite, j'ai réussi à découvrir que le problème ici vient de l'incompréhension des gens, comment obtenir un élément aléatoire d'un tableau en PHP. La tâche est simple, mais néanmoins, dès que des questions se posent, il faut y répondre.

Je vous donne le code tout de suite. Disons qu'il existe un tableau avec un ensemble de guillemets. Et vous devez en sélectionner un au hasard et afficher :

$quotes = tableau(); // Initialise un tableau vide
$quotes = "Soyez attentif à vos pensées, elles sont le début des actions."; // Première citation
$quotes = "Ce ne sont pas les plus intelligents ou les plus forts qui survivent, mais les plus réceptifs au changement."; // Deuxième citation
$quotes = "La vie est une montagne : on monte lentement, on descend vite."; // Troisième citation
$quotes = "Les gens ne veulent pas être riches, ils veulent être plus riches que les autres."; // Quatrième citation
$number = mt_rand(0, count($quotes) - 1); // Prend un nombre aléatoire de 0 à (longueur du tableau moins 1) inclus
echo $quotes[$numéro]; // Afficher un devis
?>

Le point clé est obtenir un numéro aléatoire. Tout ce que vous avez à faire est de fixer les bonnes limites. Si vous devez sélectionner un élément aléatoire sur toute la longueur du tableau, cela vient de 0 avant ( longueur du tableau moins 1). Et puis juste extraire un élément du tableau avec l'index aléatoire résultant.

Quant à la tâche avec guillemets, il vaut mieux les stocker dans une base de données. En principe, si le site est très simple, cela peut être réalisé dans un fichier texte. Mais si dans une base de données, il est préférable d'utiliser RAND() Et LIMITE V requête SQL, afin que vous receviez immédiatement un devis unique et aléatoire de la base de données.

  • Depuis:
  • Inscrit: 2014.07.07
  • Des postes: 3,775
  • J'aime juste PunBB :
  • 5 années, 6 mois,
  • Aime: 463

Sujet : Comment sélectionner une valeur aléatoire dans un tableau en PHP

En utilisant cette fonction, nous pouvons sélectionner un ou plusieurs éléments aléatoires du tableau. Oui, exactement le ou les éléments ! Cela peut être un élément ou il peut y en avoir plusieurs. Tout dépend de la tâche à laquelle vous faites face.

Cependant, il faut ici tenir compte du fait que la fonction ne renverra pas la valeur de l'élément, mais sa clé (ou ses clés, s'il y a plusieurs éléments).

La fonction prend comme paramètres entre parenthèses : le nom du tableau avec lequel nous travaillons et le nombre d'éléments à sélectionner.

En général, tout est simple ! Et ce sera encore plus facile si nous regardons tout cela avec des exemples.

Commençons par sélectionner un seul élément aléatoire dans le tableau.

2 Répondre par Jeu de motsBB

  • Depuis: Moscou, Sovkhoznay 3, app. 98
  • Inscrit: 2014.07.07
  • Des postes: 3,775
  • J'aime juste PunBB :
  • 5 années, 6 mois,
  • Aime: 463

Imaginons que quelque part en haut de notre site Web, nous souhaitions afficher des citations. Bien entendu, les citations doivent changer. Chaque fois qu'un utilisateur visite votre site, vous souhaitez qu'il voie un nouveau devis.

Comme vous l'avez probablement deviné, le moyen le plus simple de mettre en œuvre ceci est de placer toutes les citations et dictons disponibles dans un tableau, puis de sélectionner un élément aléatoire dans ce tableau et de l'afficher à l'écran.

Plus vous avez de guillemets dans le tableau, moins ils sont susceptibles d'être répétés.

Mais à titre d’exemple, je ne m’embêterai pas trop et je mettrai 7 dictons dans mon tableau.

Ensuite, je devrai créer une variable dans laquelle je stockerai le résultat de la fonction array_rand(). Entre parenthèses, cette fonction aura deux arguments : le nom de notre tableau et le nombre d'éléments aléatoires dont nous avons besoin.

Comme je l'ai déjà dit, la fonction ne renvoie pas la valeur de l'élément, mais sa clé (ou son numéro dans la liste). Ainsi, la clé de l'élément aléatoire sera stockée dans la variable.

Ensuite, il me suffit d'afficher la valeur de l'élément souhaité. Pour ce faire, j'indique le nom du tableau et entre crochets le nom de notre variable, qui contient une clé aléatoire.

C'est tout. Regardez le code ci-dessous et je pense que vous comprendrez tout complètement :

". $frases[$rand_frases] .""; ?>

3 Répondre par Jeu de motsBB

  • Depuis: Moscou, Sovkhoznay 3, app. 98
  • Inscrit: 2014.07.07
  • Des postes: 3,775
  • J'aime juste PunBB :
  • 5 années, 6 mois,
  • Aime: 463

Re : Comment sélectionner une valeur aléatoire dans un tableau en PHP

Pratiquons maintenant à imprimer quelques éléments de tableau aléatoires.

Dans le cas d'un élément, sa clé est renvoyée, et dans le cas de plusieurs éléments de tableau aléatoires, un tableau de clés est renvoyé. C'est de là que nous partirons lors de l'affichage à l'écran.

Commençons par créer un tableau dans lequel nous ajouterons 7 noms différents.

Ensuite, nous créons une variable dans laquelle le travail de la fonction array_rand() sera enregistré. Seulement maintenant, entre parenthèses pour cette fonction, nous indiquons le chiffre « 2 » comme deuxième argument. Cela signifie que nous avons besoin de 2 éléments aléatoires.

Le résultat de la fonction dans cette situation sera un tableau contenant deux clés aléatoires d'éléments de notre tableau principal.

Par conséquent, lors de l'affichage à l'écran, vous devez en tenir compte et indiquer entre crochets non seulement le nom de la variable, mais le nom de la variable, puis les crochets et l'index du tableau. Puisque nous avons 2 éléments, dans le premier cas l'index sera , et dans le second . (Vous vous souvenez que l'indexation dans les tableaux commence à "0".)

C'est tout. Jetez un œil au code pour que les choses soient plus claires :

$names = array("Masha", "Sasha", "Nadya", "Mila", "Andrey", "Sergey", "Anton"); $rand_names = array_rand($names,2); écho "

".$names[$rand_names]." et ".$names[$rand_names]."

";

En conséquence, deux noms aléatoires seront affichés à l’écran. Chaque fois que la page est actualisée, les noms changeront.

Source

Les nombres aléatoires font partie intégrante de la programmation, notamment lorsqu'il s'agit de systèmes de sécurité. Par exemple, la cryptographie repose sur la génération de valeurs aléatoires pour produire des nombres impossibles à prédire. Bien sûr, en PHP, les nombres aléatoires jouent un rôle énorme : avec leur aide, nous pouvons générer des jetons, des sels et d'autres valeurs.

La génération de nombres aléatoires est basée sur des algorithmes spéciaux. Le paramètre d'entrée à partir duquel l'algorithme démarrera peut être soit une valeur aléatoire, soit une valeur prédéterminée.

Dans cet article, nous parlerons des nombres aléatoires : comment ils sont générés et où ils peuvent être utilisés.

Utiliser des nombres aléatoires

En PHP, les nombres aléatoires jouent un rôle énorme car... très souvent utilisé à des fins diverses. Fondamentalement, ils sont liés à la sécurité. Sur cette base, des jetons CSRF, des clés API, des valeurs d'authentification, des valeurs de réinitialisation de mot de passe et bien plus encore sont générés. Tout cela est fait pour que la valeur résultante soit impossible à prédire.

Les exemples les plus importants d'utilisation de valeurs aléatoires sont :

  • Générer du sel pour la cryptographie- un nombre de sel aléatoire est généralement utilisé pour le cryptage unidirectionnel, ainsi que pour le hachage des mots de passe. Cette valeur aléatoire est utilisée comme vecteur d'initialisation en cryptographie.
  • Générer des valeurs aléatoires telles que l'ID de session- PHP est utilisé pour créer un grand nombre d'applications où la sécurité passe avant tout. De nombreuses fonctionnalités sont basées sur l'utilisation de sessions et d'ID de session générés.
  • Génération de jetons d'authentification presque impossibles à prédire- De nombreuses applications PHP sont basées sur le travail avec d'autres systèmes via des interfaces API spéciales. En règle générale, vous devez passer par un processus d'authentification avant d'utiliser une API. Il est très difficile d'obtenir des valeurs difficiles à trouver pour les jetons. C'est pourquoi des nombres aléatoires sont utilisés dans ces problèmes.

Générateurs de nombres aléatoires

Les nombres aléatoires utilisés dans les cas décrits ci-dessus sont générés par des pseudo-générateurs en PHP. Plusieurs algorithmes sont disponibles :

    Méthode congruente linéaire, lors de l'utilisation de la fonction lcg_value().

    Vortex de Mersenne, utilisé par la fonction mt_rand().

    La fonction rand() utilise une fonction similaire en langage C.

En fait, ces fonctions ne renvoient pas des nombres aléatoires, mais des nombres distribués de telle manière qu’ils semblent aléatoires. La séquence de ces nombres dépend du nombre aléatoire sous-jacent dans l'algorithme implémenté.

Numéros de base pour les générateurs

Les nombres de base ou vecteurs de nombres de base sont des ensembles de données utilisés pour générer des nombres aléatoires. Les générateurs de nombres pseudo-aléatoires ne fonctionnent qu'à partir d'eux. Si un attaquant connaît ce nombre de base, il pourra à l'avenir prédire les valeurs de vos nombres aléatoires.

En PHP, vous pouvez spécifier des nombres de base de deux manières. La première utilise la fonction mt_srand(). Cette méthode est principalement utilisée dans les tests unitaires d’une série aléatoire. La deuxième façon consiste à laisser PHP générer lui-même les nombres de base. Depuis la version 4.2, PHP propose cette fonctionnalité. Par la suite, le Vortex de Mersenne sera utilisé pour générer des nombres aléatoires.

PHP génère un numéro de base, en fonction du système d'exploitation. Sur les plateformes Linux, vous pouvez utiliser les fonctions mcrypt_create_iv() ou openssl_pseudo_random_bytes() dans /dev/urandom. Windows fournit un pseudo-générateur spécial accessible via les fonctions openssl_pseudo_random_bytes() et mcrypt_create_iv().

Conclusion

Étant donné que les nombres aléatoires jouent un rôle important dans la création d’applications Web sécurisées, nous devons en savoir plus sur leur fonctionnement. Si vous souhaitez générer vous-même des numéros de base pour les pseudo-générateurs, assurez-vous que vos méthodes sont fiables.