1931 votes

Comment générer une chaîne alphanumérique aléatoire ?

J'ai cherché un simple Algorithme Java permettant de générer une chaîne alphanumérique pseudo-aléatoire. Dans mon cas, cette chaîne serait utilisée comme identifiant unique de la session/clé, qui serait "probablement" unique sur plus d'un million d'ordinateurs. 500K+ (mes besoins ne nécessitent pas vraiment quelque chose de plus sophistiqué).

Idéalement, je pourrais spécifier une longueur en fonction de mes besoins d'unicité. Par exemple, une chaîne générée d'une longueur de 12 pourrait ressembler à ceci "AEYGF7K0DM1X" .

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.

114voto

En une ligne :

Long.toHexString(Double.doubleToLongBits(Math.random()));

Source : Java - génération d'une chaîne aléatoire

89voto

for3st Points 2727

Ceci est facilement réalisable sans aucune bibliothèque externe.

1. Génération de données pseudo-aléatoires cryptographiques (PRNG)

Vous avez d'abord besoin d'un PRNG cryptographique. Java a SecureRandom pour cela et utilise généralement la meilleure source d'entropie de la machine (par ex. /dev/random ). Plus d'informations ici .

SecureRandom rnd = new SecureRandom();
byte[] token = new byte[byteLength];
rnd.nextBytes(token);

Note : SecureRandom est la méthode la plus lente, mais la plus sûre de Java pour générer des octets aléatoires. Je recommande cependant no Il n'est pas nécessaire de tenir compte des performances ici, car elles n'ont généralement pas d'impact réel sur votre application, sauf si vous devez générer des millions de jetons par seconde.

2. Espace requis pour les valeurs possibles

Ensuite, vous devez décider du "degré d'unicité" de votre jeton. Le seul et unique intérêt de prendre en compte l'entropie est de s'assurer que le système peut résister aux attaques par force brute : l'espace des valeurs possibles doit être si grand qu'un attaquant ne puisse essayer qu'une proportion négligeable des valeurs en un temps non ridicule 1 .

Des identifiants uniques, tels que des UUID ont 122 bits d'entropie (soit 2^122 = 5,3x10^36) - le risque de collision est "*(...) pour qu'il y ait une chance sur un milliard de duplication, il faut générer 103 trillions d'UUID version 4 2 ". Nous choisirons 128 bits car ils tiennent exactement dans 16 octets. et est considéré comme hautement suffisant pour être unique dans tous les cas d'utilisation, sauf les plus extrêmes, et vous n'avez pas à vous soucier des doublons. Voici un tableau comparatif simple de l'entropie, comprenant une analyse simple de l'entropie de l problème d'anniversaire .

Comparison of token sizes

Pour des besoins simples, une longueur de 8 ou 12 octets peut suffire, mais avec 16 octets, vous êtes du "bon côté".

Et c'est à peu près tout. La dernière chose à faire est de penser à l'encodage pour qu'il puisse être représenté sous la forme d'un texte imprimable (lisez, un String ).

3. Encodage binaire en texte

Les codages typiques comprennent :

  • Base64 chaque caractère est codé sur 6 bits, ce qui crée une surcharge de 33%. Heureusement, il existe des implémentations standard en Java 8+. y Android . Avec les anciennes versions de Java, vous pouvez utiliser n'importe quel de nombreuses bibliothèques tierces . Si vous voulez que vos jetons soient sécurisés par URL, utilisez l'option Sécurité de l'URL version de la RFC4648 (qui est généralement prise en charge par la plupart des implémentations). Exemple de codage de 16 octets avec remplissage : XfJhfv3C0P6ag7y9VQxSbw==

  • Base32 chaque caractère est codé sur 5 bits, ce qui crée une surcharge de 40%. Cela utilisera A-Z y 2-7 ce qui lui permet d'être raisonnablement peu encombrant tout en étant alphanumérique et insensible à la casse. Il n'y a pas de implémentation standard dans le JDK . Exemple de codage de 16 octets sans remplissage : WUPIL5DQTZGMF4D3NX5L7LNFOY

  • Base16 (hexadécimal) chaque caractère encode quatre bits, ce qui nécessite deux caractères par octet (c'est-à-dire que 16 octets créent une chaîne de longueur 32). Par conséquent, l'hexadécimal est moins efficace en termes d'espace que l'hexadécimal. Base32 mais il peut être utilisé en toute sécurité dans la plupart des cas (URL) puisqu'il n'utilise que la fonction 0-9 y A à F . Exemple de codage de 16 octets : 4fa3dd0f57cb3bf331441ed285b27735 . Voir une discussion de Stack Overflow sur la conversion en hexadécimal ici. .

Des encodages supplémentaires comme Base85 et l'exotique Base122 existent avec une meilleure/mauvaise efficacité spatiale. Vous pouvez créer votre propre encodage (ce que font la plupart des réponses dans ce fil), mais je vous le déconseille si vous n'avez pas d'exigences très spécifiques. Voir plus de schémas d'encodage dans l'article Wikipedia .

4. Résumé et exemple

  • Utilisez SecureRandom
  • Utiliser au moins 16 octets (2^128) de valeurs possibles
  • Encodez en fonction de vos besoins (généralement hex o base32 si vous avez besoin qu'il soit alpha-numérique)

Ne fais pas ça.

  • ... utiliser votre encodage maison : _plus facile à maintenir et à lire pour les autres s'ils voient quel encodage standard vous utilisez au lieu d'encodages bizarres pour des boucles créant des personnages à la fois._
  • ... utiliser l'UUID : il n'a aucune garantie sur le caractère aléatoire ; vous gaspillez 6 bits d'entropie et vous avez une représentation en chaîne verbeuse

Exemple : Générateur de jetons hexadécimaux

public static String generateRandomHexToken(int byteLength) {
    SecureRandom secureRandom = new SecureRandom();
    byte[] token = new byte[byteLength];
    secureRandom.nextBytes(token);
    return new BigInteger(1, token).toString(16); // Hexadecimal encoding
}

//generateRandomHexToken(16) -> 2189df7475e96aa3982dbeab266497cd

Exemple : Générateur de jetons Base64 (URL Safe)

public static String generateRandomBase64Token(int byteLength) {
    SecureRandom secureRandom = new SecureRandom();
    byte[] token = new byte[byteLength];
    secureRandom.nextBytes(token);
    return Base64.getUrlEncoder().withoutPadding().encodeToString(token); //base64 encoding
}

//generateRandomBase64Token(16) -> EEcCCAYuUcQk7IuzdaPzrg

Exemple : Outil Java CLI

Si vous voulez un outil CLI prêt à l'emploi, vous pouvez utiliser dés :

Exemple : Question connexe - Protéger vos identifiants actuels

Si vous disposez déjà d'un identifiant que vous pouvez utiliser (par exemple, un identifiant synthétique long dans votre entité), mais ne veulent pas publier la valeur interne vous pouvez utiliser cette bibliothèque pour le crypter et l'obscurcir : https://github.com/patrickfav/id-mask

IdMask<Long> idMask = IdMasks.forLongIds(Config.builder(key).build());
String maskedId = idMask.mask(id);
// Example: NPSBolhMyabUBdTyanrbqT8
long originalId = idMask.unmask(maskedId);

42voto

dfa Points 54490

Utilisation de Dollar devrait être aussi simple que :

// "0123456789" + "ABCDE...Z"
String validCharacters = $('0', '9').join() + $('A', 'Z').join();

String randomString(int length) {
    return $(validCharacters).shuffle().slice(length).toString();
}

@Test
public void buildFiveRandomStrings() {
    for (int i : $(5)) {
        System.out.println(randomString(12));
    }
}

Ça donne quelque chose comme ça :

DKL1SBH9UJWC
JH7P0IT21EA5
5DTI72EO6SFU
HQUMJTEBNF7Y
1HCR6SKYWGT7

36voto

Apocalisp Points 22526

Le voici en Java :

import static java.lang.Math.round;
import static java.lang.Math.random;
import static java.lang.Math.pow;
import static java.lang.Math.abs;
import static java.lang.Math.min;
import static org.apache.commons.lang.StringUtils.leftPad

public class RandomAlphaNum {
  public static String gen(int length) {
    StringBuffer sb = new StringBuffer();
    for (int i = length; i > 0; i -= 12) {
      int n = min(12, abs(i));
      sb.append(leftPad(Long.toString(round(random() * pow(36, n)), 36), n, '0'));
    }
    return sb.toString();
  }
}

Voici un exemple d'exécution :

scala> RandomAlphaNum.gen(42)
res3: java.lang.String = uja6snx21bswf9t89s00bxssu8g6qlu16ffzqaxxoy

35voto

user unknown Points 15555

Une solution courte et facile, mais qui n'utilise que des minuscules et des chiffres :

Random r = new java.util.Random ();
String s = Long.toString (r.nextLong () & Long.MAX_VALUE, 36);

La taille est d'environ 12 chiffres en base 36 et ne peut être améliorée davantage, de cette façon. Bien sûr, vous pouvez ajouter plusieurs instances.

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