Je vais publier une réponse car certaines des réponses existantes sont proches mais ont l'une des suivantes:
- un espace de caractère plus petit que ce que vous vouliez afin que soit le forçage brutal soit plus facile, soit le mot de passe doit être plus long pour la même entropie
- un RNG qui n'est pas considéré comme sécurisé cryptographiquement
- une exigence pour une bibliothèque tierce et j'ai pensé qu'il pourrait être intéressant de montrer ce qu'il faudrait pour le faire vous-même
Cette réponse contournera le count/strlen
problème car la sécurité du mot de passe généré, du moins à mon humble avis, transcende la façon dont vous y parvenez. Je vais également supposer que PHP> 5.3.0.
Décomposons le problème en ses parties constituantes qui sont:
- utiliser une source sécurisée d'aléa pour obtenir des données aléatoires
- utiliser ces données et les représenter comme une chaîne imprimable
Pour la première partie, PHP> 5.3.0 fournit la fonction openssl_random_pseudo_bytes
. Notez que bien que la plupart des systèmes utilisent un algorithme cryptographique fort, vous devez vérifier afin que nous utilisions un wrapper:
function strong_random_bytes($length)
{
$strong = false;
$bytes = openssl_random_pseudo_bytes($length, $strong);
if ( ! $strong)
{
throw new Exception('Strong algorithm not available for PRNG.');
}
return $bytes;
}
Pour la deuxième partie, nous utiliserons base64_encode
car il prend une chaîne d'octets et produira une série de caractères qui ont un alphabet très proche de celui spécifié dans la question d'origine. Si ne nous dérangeait pas avoir +
, /
et les =
caractères apparaissent dans la chaîne finale et nous voulons un résultat au moins $n
caractères, nous pourrions simplement utiliser:
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
Le 3/4
facteur est dû au fait que le codage en base64 aboutit à une chaîne dont la longueur est au moins un tiers plus grande que la chaîne d'octets. Le résultat sera exact pour $n
être un multiple de 4 et jusqu'à 3 caractères de plus sinon. Étant donné que les caractères supplémentaires sont principalement le caractère de remplissage =
, si, pour une raison quelconque, nous avions pour contrainte que le mot de passe soit d'une longueur exacte, nous pouvons le tronquer à la longueur souhaitée. Ceci est notamment dû au fait que pour un $n
mot de passe donné , tous les mots de passe se termineraient par le même nombre de ceux-ci, de sorte qu'un attaquant ayant accès à un mot de passe de résultat aurait jusqu'à 2 caractères de moins à deviner.
Pour obtenir un crédit supplémentaire, si nous voulions respecter les spécifications exactes comme dans la question du PO, nous devrons faire un peu plus de travail. Je vais renoncer à l'approche de conversion de base ici et aller avec une approche rapide et sale. Les deux doivent générer plus de caractère aléatoire que ce qui sera utilisé dans le résultat de toute façon en raison de l'alphabet de 62 entrées.
Pour les caractères supplémentaires dans le résultat, nous pouvons simplement les supprimer de la chaîne résultante. Si nous commençons avec 8 octets dans notre chaîne d'octets, alors jusqu'à environ 25% des caractères base64 seraient ces caractères "indésirables", de sorte que le simple fait de rejeter ces caractères aboutit à une chaîne pas plus courte que l'OP souhaité. Ensuite, nous pouvons simplement le tronquer pour obtenir la longueur exacte:
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
Si vous générez des mots de passe plus longs, le caractère de remplissage =
forme une proportion de plus en plus petite du résultat intermédiaire afin que vous puissiez implémenter une approche plus légère, si le drainage du pool d'entropie utilisé pour le PRNG est un problème.