L'utilisation des UUID n'est pas sûre, car certaines parties de l'UUID ne sont pas du tout aléatoires. Le site procédure d'erickson est très soigné, mais il ne crée pas de chaînes de même longueur. L'extrait suivant devrait suffire :
/*
* The random generator used by this class to create random keys.
* In a holder class to defer initialization until needed.
*/
private static class RandomHolder {
static final Random random = new SecureRandom();
public static String randomKey(int length) {
return String.format("%"+length+"s", new BigInteger(length*5/*base 32,2^5*/, random)
.toString(32)).replace('\u0020', '0');
}
}
Pourquoi choisir length*5
? Supposons le cas simple d'une chaîne aléatoire de longueur 1, donc un caractère aléatoire. Pour obtenir un caractère aléatoire contenant tous les chiffres 0-9 et les caractères a-z, nous aurions besoin d'un nombre aléatoire entre 0 et 35 pour obtenir un de chaque caractère.
BigInteger
fournit un constructeur pour générer un nombre aléatoire, uniformément distribué sur l'intervalle 0 to (2^numBits - 1)
. Malheureusement, 35 n'est pas un nombre qui peut être reçu par 2^numBits - 1.
Nous avons donc deux options : Soit aller avec 2^5-1=31
o 2^6-1=63
. Si nous choisissions 2^6
nous obtiendrions beaucoup de numéros "inutiles" / "longs". C'est pourquoi 2^5
est la meilleure option, même si nous perdons quatre caractères (w-z). Pour générer maintenant une chaîne de caractères d'une certaine longueur, nous pouvons simplement utiliser une fonction 2^(length*numBits)-1
numéro. Le dernier problème, si nous voulons une chaîne de caractères d'une certaine longueur, le hasard pourrait générer un petit nombre, donc la longueur n'est pas respectée, nous devons donc compléter la chaîne de caractères à sa longueur requise en ajoutant des zéros.
162 votes
Méfiez-vous de le paradoxe de l'anniversaire .
62 votes
Même en tenant compte du paradoxe de l'anniversaire, si vous utilisez 12 caractères alphanumériques (62 au total), il vous faudrait encore bien plus de 34 milliards de chaînes de caractères pour atteindre le paradoxe. Et le paradoxe d'anniversaire ne garantit pas une collision de toute façon, il dit juste qu'il y a plus de 50% de chances.
6 votes
@NullUserException 50 % de chance de succès (par essai) est sacrément élevé : même avec 10 essais, le taux de succès est de 0,999. En gardant cela à l'esprit et le fait que vous pouvez essayer BEAUCOUP sur une période de 24 heures, vous n'avez pas besoin de 34 milliards de chaînes de caractères pour être pratiquement sûr de deviner au moins l'une d'entre elles. C'est la raison pour laquelle certains jetons de session doivent être très, très longs.
0 votes
Ce billet de blog devrait être utile - code pour produire des chaînes alphanumériques : rationaljava.com/2015/06/
19 votes
Ces 3 codes à une ligne sont très utiles, je suppose
Long.toHexString(Double.doubleToLongBits(Math.random()));
UUID.randomUUID().toString();
RandomStringUtils.randomAlphanumeric(12);
0 votes
La longueur n'est pas pertinente car elle dépend de l'encodage. Ce qui vous intéresse, c'est l'entropie. Une entropie de 128 bits devrait convenir à la plupart des cas d'utilisation (par exemple, 32 chiffres hexadécimaux).
25 votes
@Pijusn Je sais que c'est vieux, mais... les "50% de chance" dans le paradoxe de l'anniversaire sont... PAS "par essai", c'est "50% de chances que, sur (dans ce cas) 34 milliards de chaînes de caractères, il existe au moins une paire de doublons". Il faudrait 1,6 sept millions - 1.6e21 - d'entrées dans votre base de données pour qu'il y ait 50% de chances par essai.
1 votes
@Walt Vous avez raison, je l'ai un peu mal compris à l'époque. Mais même maintenant, je considérerais que 50% avec 36 milliards est un risque trop élevé pour une session. De plus, je ne pense pas que l'utilisation de jetons plus longs/sécurisés va introduire des problèmes significatifs.