2009-03-12 7 views
36

Je cherche à créer une fonction réutilisable qui va générer une clé aléatoire avec des caractères ACSII imprimables de longueur choisie (de 2 à 1000+). Je pense que les caractères ASCII imprimables seraient 33-126. La clé n'a pas besoin d'être complètement unique, juste unique si elle est générée exactement à la même milliseconde (donc uniqid() ne fonctionnera pas).Quel est le meilleur moyen de générer une clé aléatoire dans PHP?

Je pense qu'une combinaison de chr() et mt_rand() pourrait fonctionner.

Est-ce la voie à suivre, ou est-ce que quelque chose d'autre est la meilleure méthode?

Editer:uniqid() ne fonctionnera pas non plus car il n'a pas de paramètre de longueur, c'est juste ce que PHP vous donne.

Mon Idée: Voici ce que je suis venu avec:

function GenerateKey($length = 16) { 
    $key = ''; 

    for($i = 0; $i < $length; $i ++) { 
     $key .= chr(mt_rand(33, 126)); 
    } 

    return $key; 
} 

Y at-il des problèmes avec cela?

Autre édition: La plupart des autres questions concernent la génération de mot de passe. Je veux une plus grande variété de caractères et je me fous de 1 vs l. Je veux que le nombre maximum de clés possibles soit possible.

Remarque: la clé générée ne doit pas nécessairement être cryptographiquement sécurisée.

+0

générateurs de nombres aléatoires ne unique généralement pas _guarantee_, même si "Généré exactement la même milliseconde." Pour garantir l'unicité, vous devez être capable de détecter une collision. – danorton

+0

Ajouté gros avertissement sur la sécurité, sinon je devrais downvote chaque réponse. Soyez averti que certaines des fonctions dans les réponses retournent binaire, d'autres retournent hex, d'autres base64 etc etc. –

Répondre

54

Mise à jour (12/2015): Pour PHP 7.0, vous devez utiliser random_int() au lieu de mt_rand car il fournit des « valeurs sûres » cryptographiquement

Personnellement, je préfère utiliser sha1(microtime(true).mt_rand(10000,90000)) mais vous recherchez plus de une approche personnalisable, alors essayez cette fonction (qui est une modification à votre demande de this answer):

function rand_char($length) { 
    $random = ''; 
    for ($i = 0; $i < $length; $i++) { 
    $random .= chr(mt_rand(33, 126)); 
    } 
    return $random; 
} 

encore, ce sera probablement beaucoup plus lent que uniqid(), md5() ou SHA1().

Editer: On dirait que vous avez d'abord eu, désolé. : D

Edit 2: j'ai décidé de faire un test peu agréable sur ma machine Debian avec PHP 5 et eAccelerator (excusez le code long):

function rand_char($length) { 
    $random = ''; 
    for ($i = 0; $i < $length; $i++) { 
    $random .= chr(mt_rand(33, 126)); 
    } 
    return $random; 
} 

function rand_sha1($length) { 
    $max = ceil($length/40); 
    $random = ''; 
    for ($i = 0; $i < $max; $i ++) { 
    $random .= sha1(microtime(true).mt_rand(10000,90000)); 
    } 
    return substr($random, 0, $length); 
} 

function rand_md5($length) { 
    $max = ceil($length/32); 
    $random = ''; 
    for ($i = 0; $i < $max; $i ++) { 
    $random .= md5(microtime(true).mt_rand(10000,90000)); 
    } 
    return substr($random, 0, $length); 
} 

$a = microtime(true); 
for ($x = 0; $x < 1000; $x++) 
    $temp = rand_char(1000); 

echo "Rand:\t".(microtime(true) - $a)."\n"; 

$a = microtime(true); 
for ($x = 0; $x < 1000; $x++) 
    $temp = rand_sha1(1000); 

echo "SHA-1:\t".(microtime(true) - $a)."\n"; 

$a = microtime(true); 
for ($x = 0; $x < 1000; $x++) 
    $temp = rand_md5(1000); 

echo "MD5:\t".(microtime(true) - $a)."\n"; 

Résultats:

Rand: 2.09621596336 
SHA-1: 0.611464977264 
MD5: 0.618473052979 

Donc, ma suggestion, si vous voulez la vitesse (mais pas charset complet), est de s'en tenir à MD5, SHA-1, ou Uniqid (que je n'ai pas encore testé ..)

+1

Battez-vous juste de quelques secondes. –

+3

Battez-vous juste de quelques mois;) – lpfavreau

+0

+1 pour la réponse propre et la modification du code d'origine, celui-ci est préférable d'utiliser mt_rand() – lpfavreau

0

Est-ce que that question pourrait vous intéresser?

Je ne sais pas pourquoi uniqid() ne fonctionne pas pour vous et dans quel cas vous avez besoin d'un numéro unique dans la même milliseconde mais pas nécessairement autrement; Que générez-vous si vite que dans la même milliseconde vous pourriez avoir une collision? Je me demande combien de temps prend uniqid() juste pour générer son nombre. Si vous le souhaitez, utilisez le paramètre prefix de la fonction uniqid() avec quelques lettres au hasard et vous devriez être en sécurité. S'il s'agit de générer un fichier, vous pouvez regarder tmpfile() ou tempname(). Dans tous les cas, en fonction de ce que vous essayez de réaliser, vous pouvez simplement boucler et vérifier si l'identifiant unique est déjà pris (dans un tableau, avec file_exists, etc.) et en générer un autre si c'est le cas .


De plus, comme je ne suis pas sûr que je comprends votre question exactement, je vous indiquer les autres questions assez semblables sonnent pendant que je la différence de la vôtre:

Le premier sera d'intérêt si vous cherchez à faire un identifiant unique qui est lisible par l'homme. Le second pourrait être utile si vous voulez jouer avec des nombres aléatoires et md5/sha1. Bien que, encore une fois, je pense que uniqid() pourrait déjà être ce que vous cherchez.

7

Vous pouvez toujours se uniqid(), effectuez simplement un traitement supplémentaire pour étendre sa valeur au nombre de caractères dont vous avez besoin.

Par exemple, pour l'étendre à 32 caractères, vous pouvez faire

$id = md5(uniqid()); 

Pour l'étendre à 64 caractères, ajoutez juste le md5 du md5, comme si

$first = md5(uniqid()); 
$id = $first . md5($first); 

Ensuite, si nécessaire, si vous avez besoin de moins d'un multiple de 32.

Il est possible que vous rencontriez des collisions, mais c'est peu probable. Si vous êtes paranoïaque à ce sujet, utilisez la même idée, mais battez uniqid() à travers un chiffrement symétrique comme AES au lieu de le hacher.

27

Aucune des réponses ici ne suffit si vous voulez un caractère aléatoire de force cryptographique (y a-t-il un attaquant déterminé essayant de deviner quelles sont vos clés aléatoires?). Hashing le temps n'est pas sécurisé, un attaquant peut grandement accélérer leur recherche en devinant le moment où ils pensent que votre serveur a généré la clé, et il est facile de chercher toutes les millisecondes dans une année donnée, même sur un ordinateur portable espace de recherche de bits). En outre, la suggestion d'exécuter simplement les résultats de uniqid() ou d'une autre source aléatoire faible via une fonction de hachage pour la "développer" est dangereuse. Cela ne rend pas la recherche d'un attaquant plus difficile une fois qu'ils ont découvert que vous l'avez fait.

Si vous avez vraiment besoin de sécurité au niveau de Crypto, vous devriez lire/dev/random, le code suivant doit travailler pour vous dans tout système compatible POSIX (tout sauf Windows):

#Generate a random key from /dev/random 
function get_key($bit_length = 128){ 
    $fp = @fopen('/dev/random','rb'); 
    if ($fp !== FALSE) { 
     $key = substr(base64_encode(@fread($fp,($bit_length + 7)/8)), 0, (($bit_length + 5)/6) - 2); 
     @fclose($fp); 
     return $key; 
    } 
    return null; 
} 

Si vous besoin d'un peu plus de vitesse, vous pouvez lire à la place 'dev/urandom'.

+4

Je voulais juste noter - J'avais un script qui prenait environ 50s ou plus à charger, et il s'avère que l'utilisation de/dev/random au lieu de/dev/urandom en était la cause. Dans mon environnement de test local, cela ne s'est jamais produit. – whichdan

+4

'/ dev/urandom' devrait être la valeur par défaut, en utilisant'/dev/random/'va épuiser le pool d'entropie aléatoire trop tôt (sur les systèmes sans générateur de nombres aléatoires dédiés liés à '/ dev/random'). En fait, comme ce serait un bon moyen pour un attaquant d'effectuer une attaque DoS, je ne pense pas que la fonction devrait être exposée du tout, elle n'est utile que pour les applications/bibliothèques avec leur propre PRNG. –

3

Pourquoi ne pas utiliser openssl_random_pseudo_bytes http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php

+0

Cette réponse serait plus efficace si vous montriez un exemple de ce que cela pourrait vous apporter. – ethrbunny

+0

J'utilise avec succès ce qui précède comme suit $ sessionkey = bin2hex (openssl_random_pseudo_bytes (1024)); Cela génère une clé aléatoire cryptographiquement sûre ... C'est une réponse à .. 'la meilleure façon de générer une clé aléatoire' ... C'est un très bon moyen car ... a) il utilise une simple fonction rapide ... c'est crypo sûr, il est évidemment aléatoire .. et vous pouvez générer des clés de toute longueur ... –

0

$ key = md5 (microtime() rand().); Le microtime en lui-même n'est pas sûr car il ne laisse que 1/1000 chance d'être deviné. Rand par lui-même n'est pas non plus très sûr, mais hacher leur concaténation ensemble donne une randomisation assez solide.

+0

"Rand par lui-même est également pas très sécurisé, mais leur hachage leur concaténation ensemble donne une solide randomisation solide." Nan. Vous avez une valeur prévisible avec une limite supérieure de 32 bits d'entropie de 'rand()'. Si l'on suppose que 'microtime()' contient 10 bits d'entropie, on aboutit à environ 42 bits. Collisions d'anniversaire après tous les 2 millions d'échantillons, mais 'rand()' est prévisible. Meilleure solution: Utilisez un CSPRNG pour générer des clés. –

1

Ma réponse précédente prenait un hash de uniqid() combiné à un sel dérivé de variables système, mais qui ne générait pas de clé aléatoire , une seule susceptible d'être unique. De même, la sortie de rand() ou mt_rand() n'est pas assez aléatoire à des fins de chiffrement.

Pour générer une clé aléatoire, vous devez aller à une source de données aléatoires, et la fonction openssl_random_pseudo_bytes() est conçue pour le faire:

$randkey = base64_encode(openssl_random_pseudo_bytes(32)); 

Le base64_encode() est de faire en caractères imprimables.

La raison pour laquelle les autres réponses ne recommandent pas openssl_random_pseudo_bytes() est probablement qu'elle a été introduite en PHP 5.3, et cette question a presque 6 ans.

-1

vous pouvez également générer une clé aléatoire et vérifiez la clé dans votre base de données si la clé est sorties, vous pouvez générer une autre clé par cette méthode

 function activation($lengt=20){ 
    $modalpage =new Modal;//you can call your modal page and check the key 

    $characters = "1234567890abcdefghijklmnopqrstuvwxyz"; 
    for($i=0;$i<$lengt;$i++) 

    {  

    $key .= $characters{rand(0,35)}; 
    $check= array(
    ":key" => $key, 
    ); 

    $result = $modalpage->findkey($check); 

    if($result==true){ //if the key is exits return the function and generate another key ! 

     return activation($lengt); 

    }else //if the key is not exits return the key 
    return $key; 
    } 


      } 

$mykey=activation(15); 
Questions connexes