40 votes

Quelle est la meilleure façon de générer une clé aléatoire en PHP ?

Je cherche à créer une fonction réutilisable qui générera une clé aléatoire avec des caractères ACSII imprimables de longueur choisie (entre 2 et 1000+). Je pense que les caractères ASCII imprimables seraient de 33 à 126. La clé n'a pas besoin d'être complètement unique, mais seulement unique si elle est générée exactement à la même milliseconde (par ex. uniqid() ne fonctionnera pas).

Je pense à une combinaison de chr() y mt_rand() pourrait fonctionner.

Est-ce que c'est la bonne méthode, ou est-ce qu'une autre méthode est préférable ?

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

Mon idée : Voilà ce que j'ai trouvé :

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

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

    return $key;
}

Cela pose-t-il des problèmes ?

Une autre édition : La plupart des autres questions portent sur la génération de mots de passe. Je veux une plus grande variété de caractères et je ne me soucie pas de 1 vs l . Je veux que le nombre maximum de clés soit possible.

58voto

St. John Johnson Points 4163

Personnellement, j'aime utiliser sha1(microtime(true).mt_rand(10000,90000)) mais vous recherchez une approche plus personnalisable, alors essayez cette fonction (qui est une modification de votre demande de cette réponse ):

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

Néanmoins, cela sera probablement beaucoup plus lent que uniqid(), md5(), ou sha1().

Editar: On dirait que vous l'avez trouvé en premier, désolé. :D

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

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 de la vitesse (mais pas un jeu de caractères complet), est de s'en tenir à MD5, SHA-1, ou Uniqid (que je n'ai pas encore testé).

29voto

SecurityJoe Points 431

Aucune des réponses données ici n'est suffisante si vous souhaitez un caractère aléatoire de type cryptographique (existe-t-il un attaquant déterminé qui essaie de deviner quelles sont vos clés aléatoires ?) Le hachage de l'heure n'est pas sûr, un attaquant peut considérablement accélérer sa recherche en devinant l'heure à laquelle il pense que votre serveur a généré la clé, et il est facile de rechercher toutes les millisecondes d'une année donnée, même sur un ordinateur portable de base (c'est un espace de recherche de 35 bits). De plus, la suggestion d'exécuter simplement les résultats de uniqid() ou une autre source aléatoire faible à travers une fonction de hachage pour "l'étendre" est dangereux - cela ne rend pas la recherche d'un attaquant plus difficile une fois qu'il a découvert que vous avez fait cela.

Si vous avez vraiment besoin d'une sécurité de niveau cryptographique, vous devriez lire sur /dev/random, le code suivant devrait fonctionner 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 avez besoin d'un peu plus de vitesse, vous pouvez lire à partir de 'dev/urandom' à la place.

9voto

Bob Somers Points 4186

Vous pouvez toujours utiliser uniqid(), mais vous devez effectuer 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 ce qui suit

$id = md5(uniqid());

Pour l'étendre à 64 caractères, il suffit d'ajouter le md5 du md5, comme suit

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

Ensuite, il faut trucider si nécessaire, si vous avez besoin de moins qu'un multiple de 32.

Il est possible que vous puissiez entrer en collision, mais c'est assez peu probable. Si vous êtes paranoïaque à ce sujet, utilisez la même idée, mais en faisant du chug uniqid() par un chiffrement symétrique comme AES au lieu de le hacher.

3voto

omar-ali Points 153

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

1voto

thomasrutter Points 42905

J'aime faire quelque chose comme,

$randkey = hash('sha-256', 
  uniqid(serialize($_SERVER), true));

L'inclusion de uniqid() permet de s'assurer qu'il est unique à ce serveur. La sérialisation de $_SERVER vise à garantir que vous ne générerez pas le même hachage sur un autre serveur. Je dis "tente de" en raison de la probabilité ridiculement faible de tomber sur une collision dans SHA-256.

Notez que cela représente 64 caractères. Si c'est trop difficile à avaler, vous pouvez utiliser base64 au lieu de l'hexagone par défaut. Cela ramène le nombre de caractères à environ 43.

$randkey = base64_encode(hash('sha-256', 
  uniqid(serialize($_SERVER), true), true));

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X