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.

1624voto

erickson Points 127945

Algorithme

Pour générer une chaîne aléatoire, concaténer des caractères tirés au hasard de l'ensemble des symboles acceptables jusqu'à ce que la chaîne atteigne la longueur souhaitée.

Mise en œuvre

Voici un code assez simple et très souple pour générer des identifiants aléatoires. Lisez les informations qui suivent pour des 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éer un générateur non sécurisé pour les identifiants à 8 caractères :

RandomString gen = new RandomString(8, ThreadLocalRandom.current());

Créer 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);

Utilisation comme identifiants de session

Générer des identifiants de session susceptibles d'être uniques n'est pas suffisant, ou vous pourriez utiliser un simple compteur. Les attaquants détournent les 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 identificateurs plus longs consomment plus de stockage et de bande passante. Un ensemble plus large de symboles est utile, mais peut causer des problèmes d'encodage si les identifiants sont inclus dans les URL ou saisis à la main.

La source sous-jacente du caractère aléatoire, ou entropie, des identifiants de session doit 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 s'avérer coûteuse ou lente en termes de calcul. Il convient donc de s'efforcer de les réutiliser lorsque cela est possible.

Utilisation comme identificateurs d'objets

Toutes les applications ne nécessitent pas de sécurité. L'assignation aléatoire peut être un moyen efficace pour plusieurs entités de générer des identifiants dans un espace partagé sans coordination ni partitionnement. La coordination peut être lente, en particulier dans un environnement en grappe ou distribué, et la division d'un espace pose des problèmes lorsque les entités se retrouvent avec des parts trop petites ou trop grandes.

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 être en mesure de les visualiser et de les manipuler, comme c'est le cas 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 d'identifiants prévu. 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'identifiants effectivement générés, q est le nombre de symboles distincts dans l'alphabet, et x est la longueur des identifiants. Il doit s'agir d'un très petit nombre, comme 2. 50 ou moins.

Ce calcul montre que le risque de collision entre 500 000 identifiants de 15 caractères est d'environ 2 %. 52 ce qui est probablement moins probable que des erreurs non détectées dues aux rayons cosmiques, etc.

Comparaison avec les UUID

Selon leur spécification, UUIDs ne sont pas conçus pour être imprévisibles, et ne devrait pas être utilisés comme identifiants de session.

Dans leur format standard, les UUID occupent beaucoup d'espace : 36 caractères pour seulement 122 bits d'entropie. (Tous les bits d'un UUID "aléatoire" ne sont pas choisis 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 standardisées. C'est leur principale vertu, mais aussi leur principale faiblesse. Dans le cadre d'une collaboration avec une partie extérieure, la normalisation offerte par les UUID peut être utile. Pour un usage purement interne, ils peuvent être inefficaces.

0 votes

Votre méthode coûteuse ne fonctionne pas pour moi ! Je n'arrive pas à trouver le symbole de la méthode BigInteger(int,java.security.SecureRandom)

6 votes

Si vous avez besoin d'espaces dans les vôtres, vous pouvez rajouter .replaceAll("\\d", " "); sur l'extrémité de la return new BigInteger(130, random).toString(32); pour faire un échange de regex. Elle remplace tous les chiffres par des espaces. Cela fonctionne très bien pour moi : Je l'utilise comme substitut d'un Lorem Ipsum frontal.

4 votes

@weisjohn C'est une bonne idée. Vous pouvez faire quelque chose de similaire avec la deuxième méthode, en retirant les chiffres de symbols et en utilisant un espace à la place ; vous pouvez contrôler la longueur moyenne des "mots" en modifiant le nombre d'espaces dans les symboles (plus d'occurrences pour des mots plus courts). Pour une solution de faux texte vraiment exagérée, vous pouvez utiliser une chaîne de Markov !

886voto

Steve McLeod Points 19016

Java fournit un moyen de le faire directement. Si vous ne voulez pas des tirets, il est facile de les supprimer. Il suffit d'utiliser uuid.replace("-", "")

import java.util.UUID;

public class randomStringGenerator {
    public static void main(String[] args) {
        System.out.println(generateString());
    }

    public static String generateString() {
        String uuid = UUID.randomUUID().toString();
        return "uuid = " + uuid;
    }
}

Sortie

uuid = 2d7428a6-b58c-4008-8575-f05549f16316

36 votes

Attention, cette solution ne génère qu'une chaîne aléatoire avec des caractères hexadécimaux. Ce qui peut convenir dans certains cas.

6 votes

La classe UUID est utile. Cependant, ils ne sont pas aussi compacts que les identifiants produits par mes réponses. Cela peut être un problème, par exemple, dans les URL. Cela dépend de vos besoins.

0 votes

Si les caractères hexadécimaux vous inquiètent, il suffit de les faire passer par un algorithme de hachage cryptographique.

627voto

maxp Points 1852
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static SecureRandom rnd = new SecureRandom();

String randomString(int len){
   StringBuilder sb = new StringBuilder(len);
   for(int i = 0; i < len; i++)
      sb.append(AB.charAt(rnd.nextInt(AB.length())));
   return sb.toString();
}

71 votes

+1, la solution la plus simple ici pour générer une chaîne aléatoire de la longueur spécifiée (à part l'utilisation de RandomStringUtils de Commons Lang).

15 votes

Envisagez d'utiliser SecureRandom au lieu de la Random classe. Si les mots de passe sont générés sur un serveur, celui-ci peut être vulnérable aux attaques de synchronisation.

10 votes

J'ajouterais aussi des minuscules : AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw‌​xyz"; et d'autres caractères autorisés.

502voto

cmsherratt Points 1846

Si vous êtes heureux d'utiliser les classes Apache, vous pouvez utiliser org.apache.commons.text.RandomStringGenerator ( Texte Apache Commons ).

Exemple :

RandomStringGenerator randomStringGenerator =
        new RandomStringGenerator.Builder()
                .withinRange('0', 'z')
                .filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
                .build();
randomStringGenerator.generate(12); // toUpperCase() if you want

Depuis Langage Apache Commons 3.6, RandomStringUtils est déprécié.

23 votes

A juste regardé à travers classe mentionnée de Apache Commons Lang 3.3.1 et il n'utilise que java.util.Random pour fournir des séquences aléatoires, il produit donc séquences non sécurisées .

16 votes

Veillez à utiliser SecureRandom lorsque vous utilisez RandomStringUtils : public static java.lang.String random(int count, int start, int end, boolean letters, boolean numbers, @Nullable char[] chars, java.util.Random random)

0 votes

NE PAS UTILISER. Cela crée séquences non sécurisées !

140voto

manish_s Points 1045

Vous pouvez utiliser un Apache Commons bibliothèque pour cela, RandomStringUtils :

RandomStringUtils.randomAlphanumeric(20).toUpperCase();

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