Je souhaite créer un générateur de jetons qui génère des jetons que l'utilisateur ne puisse pas deviner et qui soient toujours uniques (à utiliser pour les réinitialisations de mot de passe et les codes de confirmation).
Je vois souvent ce code; Est-ce que ça fait du sens?
md5(uniqid(Rand(), true));
Selon un commentaireuniqid($prefix, $moreEntopy = true)
rendements
8 premiers caractères hexadécimaux = Unixtime, 5 derniers caractères hexadécimaux = microsecondes.
Je ne sais pas comment le paramètre $prefix
- est traité.
Ainsi, si vous ne définissez pas l'indicateur $ moreEntopy sur true, le résultat obtenu est prévisible.
QUESTION: _ Mais si nous utilisons uniqid
avec $moreEntopy
, qu'est-ce que le hachage avec md5 nous achète? Est-il meilleur que:
md5(mt_Rand())
edit1: Je vais stocker ce jeton dans une colonne de la base de données avec un index unique. Je vais donc détecter les colonnes. Pourrait être d'intérêt /
Rand () est un danger pour la sécurité et ne doit jamais être utilisé pour générer un jeton de sécurité: Rand () vs mt_Rand () (Regardez l'image "statique" comme des images). Mais aucune de ces méthodes de génération de nombres aléatoires n'est sécurisée par cryptographie. Pour générer des sauvegardes sécurisées, une application doit accéder à un fichier CSPRNG fourni par la plate-forme, le système d'exploitation ou le module matériel.
Dans une application Web, un bon moyen de sécuriser les secrets sécurisés est de ne pas bloquer l'accès à un pool d'entropie tel que /dev/urandom
. Depuis PHP 5.3, les applications PHP peuvent utiliser openssl_random_pseudo_bytes()
et la bibliothèque Openssl choisira la meilleure source d'entropie en fonction de votre système d'exploitation. Sous Linux, cela signifie que l'application utilisera /dev/urandom
. Ce code de Scott est plutôt bon :
function crypto_Rand_secure($min, $max) {
$range = $max - $min;
if ($range < 0) return $min; // not so random...
$log = log($range, 2);
$bytes = (int) ($log / 8) + 1; // length in bytes
$bits = (int) $log + 1; // length in bits
$filter = (int) (1 << $bits) - 1; // set all lower bits to 1
do {
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
$rnd = $rnd & $filter; // discard irrelevant bits
} while ($rnd >= $range);
return $min + $rnd;
}
function getToken($length=32){
$token = "";
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
$codeAlphabet.= "0123456789";
for($i=0;$i<$length;$i++){
$token .= $codeAlphabet[crypto_Rand_secure(0,strlen($codeAlphabet))];
}
return $token;
}
Ceci est une copie d'une autre question que j'ai trouvée qui avait été posée quelques mois avant celle-ci. Voici un lien vers la question et ma réponse: https://stackoverflow.com/a/13733588/1698153 .
Je ne suis pas d'accord avec la réponse acceptée. Selon le site Web de la PHP "[uniqid] does not generate cryptographically secure tokens, in fact without being passed any additional parameters the return value is little different from microtime(). If you need to generate cryptographically secure tokens use openssl_random_pseudo_bytes()."
Je ne pense pas que la réponse puisse être plus claire que cela, uniqid
n'est pas sécurisé.
Définir "unique". Si vous voulez dire que deux jetons ne peuvent pas avoir la même valeur, le hachage ne suffit pas, il doit être complété par un test d'unicité. Le fait que vous fournissiez à l'algorithme de hachage des entrées uniques ne garantit pas des sorties uniques.
Pour répondre à votre question, le problème est qu’il est impossible de créer un générateur aléatoire et unique, c’est-à-dire que md5(mt_Rand())
peut conduire à des doublons. Ce que vous voulez, c'est des valeurs uniques "apparaissant au hasard". uniqid donne l'identifiant unique, Rand () appose un nombre aléatoire le rendant encore plus difficile à deviner, md5 masque le résultat pour le rendre encore plus difficile à deviner. Rien n'est indestructible. Nous devons juste rendre la tâche si difficile qu'ils ne voudraient même pas essayer.
J'ai eu une idée intéressante il y a quelques années.
Stocker deux valeurs de hachage dans la base de données, l’une générée avec md5 ($ a) et l’autre avec sha ($ a). Puis vérifiez si les deux valeurs sont correctes. Le point est, si l'attaquant a brisé votre md5 (), il ne peut pas briser votre md5 et sha dans un proche avenir.
Le problème est le suivant: comment utiliser ce concept avec la génération de jeton nécessaire à votre problème?
Premièrement, la portée de ce type de procédure est de créer une clé/hachage/code, qui sera unique pour une base de données donnée. Il est impossible de créer quelque chose d'unique pour le monde entier à un moment donné ..__ Cela étant dit, vous devez créer une chaîne simple et visible en utilisant un alphabet personnalisé et en comparant le code créé à votre base de données (table). Si cette chaîne est unique, vous lui appliquez une md5()
et personne ni aucun script ne peut le deviner. Je sais que si vous approfondissez la théorie de la génération cryptographique, vous trouverez de nombreuses explications sur ce type de génération de code, mais lorsque vous l'utilisez réellement, ce n'est pas si compliqué.
Voici le code que j'utilise pour générer un code unique simple à 10 chiffres.
$alphabet = "aA1!bB2@cC3#dD5%eE6^fF7&gG8*hH9(iI0)jJ4-kK=+lL[mM]nN{oO}pP\qQ/rR,sS.tT?uUvV>xX~yY|zZ`wW$";
$code = '';
$alplhaLenght = strlen($alphabet )-1;
for ($i = 1; $i <= 10; $i++) {
$n = Rand(1, $alplhaLenght );
$code .= $alphabet [$n];
}
Et voici quelques codes générés, bien que vous puissiez l’exécuter vous-même pour le voir fonctionner:
SpQ0T0tyO%
Uwn [MU] [.
D | [ROt + Cd @
O6I | w38TRe
Bien sûr, il peut y avoir beaucoup "d'améliorations" qui peuvent être appliquées, pour le rendre plus "compliqué", mais si vous appliquez un md5()
à cela, il deviendra, disons "indiscutable". :)