Algorithme
Pour générer une chaîne aléatoire, concaténez des caractères tirés au hasard à partir de l'ensemble de symboles acceptables jusqu'à ce que la chaîne atteigne la longueur souhaitée.
la mise en oeuvre
Voici un code assez simple et très flexible pour générer des identificateurs aléatoires. Lisez les informations qui suivent pour les notes d'application importantes.
public class RandomString {
/**
* Generate a random string.
*/
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String lower = upper.toLowerCase(Locale.ROOT);
public static final String digits = "0123456789";
public static final String alphanum = upper + lower + digits;
private final Random random;
private final char[] symbols;
private final char[] buf;
public RandomString(int length, Random random, String symbols) {
if (length < 1) throw new IllegalArgumentException();
if (symbols.length() < 2) throw new IllegalArgumentException();
this.random = Objects.requireNonNull(random);
this.symbols = symbols.toCharArray();
this.buf = new char[length];
}
/**
* Create an alphanumeric string generator.
*/
public RandomString(int length, Random random) {
this(length, random, alphanum);
}
/**
* Create an alphanumeric strings from a secure generator.
*/
public RandomString(int length) {
this(length, new SecureRandom());
}
/**
* Create session identifiers.
*/
public RandomString() {
this(21);
}
}
Exemples d'utilisation
Créez un générateur non sécurisé pour les identifiants à 8 caractères:
RandomString gen = new RandomString(8, ThreadLocalRandom.current());
Créez un générateur sécurisé pour les identifiants de session:
RandomString session = new RandomString();
Créez un générateur avec des codes faciles à lire pour l'impression. Les chaînes sont plus longues que les chaînes alphanumériques complètes pour compenser l'utilisation de moins de symboles:
String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);
Utiliser comme identificateurs de session
Générer des identifiants de session susceptibles d'être uniques n'est pas suffisant, ou vous pouvez simplement utiliser un simple compteur. Les attaquants détournent des sessions lorsque des identifiants prévisibles sont utilisés.
Il existe une tension entre la longueur et la sécurité. Les identifiants plus courts sont plus faciles à deviner, car il y a moins de possibilités. Mais les identifiants plus longs consomment plus de stockage et de bande passante. Un plus grand ensemble de symboles est utile, mais peut entraîner des problèmes de codage si les identifiants sont inclus dans les URL ou saisis à nouveau manuellement.
La source sous-jacente d'aléatoire, ou d'entropie, pour les identificateurs de session devrait provenir d'un générateur de nombres aléatoires conçu pour la cryptographie. Cependant, l'initialisation de ces générateurs peut parfois être coûteuse ou lente en termes de calcul, il convient donc de s'efforcer de les réutiliser lorsque cela est possible.
Utiliser comme identificateurs d'objet
Toutes les applications ne nécessitent pas de sécurité. L'affectation aléatoire peut être un moyen efficace pour plusieurs entités de générer des identifiants dans un espace partagé sans aucune coordination ni partitionnement. La coordination peut être lente, en particulier dans un environnement en cluster ou distribué, et la division d'un espace provoque des problèmes lorsque les entités se retrouvent avec des partages trop petits ou trop grands.
Les identifiants générés sans prendre de mesures pour les rendre imprévisibles doivent être protégés par d'autres moyens si un attaquant peut les voir et les manipuler, comme cela se produit dans la plupart des applications Web. Il devrait y avoir un système d'autorisation distinct qui protège les objets dont l'identifiant peut être deviné par un attaquant sans autorisation d'accès.
Il faut également veiller à utiliser des identifiants suffisamment longs pour rendre les collisions improbables compte tenu du nombre total prévu d'identifiants. C'est ce qu'on appelle «le paradoxe de l'anniversaire». La probabilité d'une collision, p , est d'environ n 2 / (2q x ), où n est le nombre d'identificateurs réellement générés, q est le nombre de symboles distincts dans l'alphabet et x est la longueur des identificateurs. Ce devrait être un très petit nombre, comme 2 à 50 ou moins.
Ce travail montre que le risque de collision entre 500k identificateurs à 15 caractères est d'environ 2 à 52 , ce qui est probablement moins probable que les erreurs non détectées des rayons cosmiques, etc.
Comparaison avec les UUID
Selon leur spécification, les UUID ne sont pas conçus pour être imprévisibles et ne doivent pas être utilisés comme identificateurs de session.
Les UUID dans leur format standard prennent beaucoup de place: 36 caractères pour seulement 122 bits d'entropie. (Tous les bits d'un UUID "aléatoire" ne sont pas sélectionnés au hasard.) Une chaîne alphanumérique choisie au hasard contient plus d'entropie en seulement 21 caractères.
Les UUID ne sont pas flexibles; ils ont une structure et une disposition normalisées. C'est leur principale vertu ainsi que leur principale faiblesse. Lorsque vous collaborez avec un tiers, la standardisation offerte par les UUID peut être utile. Pour un usage purement interne, ils peuvent être inefficaces.