1975 Stimmen

Wie man eine zufällige alphanumerische Zeichenfolge erzeugt

Ich habe nach einem einfach Java-Algorithmus zur Erzeugung einer pseudo-zufälligen alphanumerischen Zeichenkette. In meinem Fall würde sie als eindeutiger Sitzungs-/Schlüsselbezeichner verwendet, der "wahrscheinlich" in folgenden Fällen eindeutig ist 500K+ Generation (meine Bedürfnisse erfordern nicht wirklich etwas viel Anspruchsvolleres).

Im Idealfall könnte ich eine Länge angeben, die meinen Bedürfnissen nach Einzigartigkeit entspricht. Eine generierte Zeichenkette der Länge 12 könnte zum Beispiel wie folgt aussehen "AEYGF7K0DM1X" .

166 Stimmen

64 Stimmen

Selbst wenn man das Geburtstagsparadoxon in Betracht zieht, bräuchte man bei Verwendung von 12 alphanumerischen Zeichen (62 insgesamt) immer noch weit über 34 Milliarden Zeichenfolgen, um das Paradoxon zu erreichen. Und das Geburtstagsparadoxon garantiert sowieso keine Kollision, es sagt nur, dass die Wahrscheinlichkeit über 50 % liegt.

6 Stimmen

@NullUserException 50 % Erfolgschance (pro Versuch) ist verdammt hoch: Selbst bei 10 Versuchen liegt die Erfolgsquote bei 0,999. Wenn man das und die Tatsache bedenkt, dass man innerhalb von 24 Stunden VIELE Versuche machen kann, braucht man keine 34 Milliarden Zeichenfolgen, um ziemlich sicher zu sein, dass man mindestens eine davon errät. Das ist der Grund, warum einige Sitzungs-Tokens sehr, sehr lang sein sollten.

1633voto

erickson Punkte 256579

Algorithmus

Um eine zufällige Zeichenkette zu erzeugen, fügen Sie Zeichen aus der Menge der zulässigen Symbole nach dem Zufallsprinzip aneinander, bis die Zeichenkette die gewünschte Länge erreicht.

Umsetzung

Hier ist ein relativ einfacher und sehr flexibler Code zur Erzeugung von Zufallsidentifikatoren. Lesen Sie die folgenden Informationen für wichtige Anwendungshinweise.

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);
    }

}

Beispiele für den Gebrauch

Erstellen Sie einen unsicheren Generator für 8-stellige Kennungen:

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

Erstellen Sie einen sicheren Generator für Sitzungskennungen:

RandomString session = new RandomString();

Erstellen Sie einen Generator mit leicht lesbaren Codes für den Druck. Die Zeichenfolgen sind länger als vollständige alphanumerische Zeichenfolgen, um die Verwendung weniger Symbole auszugleichen:

String easy = RandomString.digits + "ACEFGHJKLMNPQRUVWXYabcdefhijkprstuvwx";
RandomString tickets = new RandomString(23, new SecureRandom(), easy);

Verwendung als Sitzungskennzeichen

Es reicht nicht aus, Sitzungskennungen zu generieren, die wahrscheinlich eindeutig sind, oder einen einfachen Zähler zu verwenden. Angreifer kapern Sitzungen, wenn vorhersehbare Bezeichner verwendet werden.

Es besteht ein Spannungsverhältnis zwischen Länge und Sicherheit. Kürzere Kennungen sind leichter zu erraten, weil es weniger Möglichkeiten gibt. Längere Bezeichner verbrauchen jedoch mehr Speicherplatz und Bandbreite. Ein größerer Satz von Symbolen ist hilfreich, kann aber zu Verschlüsselungsproblemen führen, wenn Bezeichner in URLs enthalten sind oder von Hand neu eingegeben werden.

Die zugrundeliegende Zufallsquelle oder Entropie für Sitzungskennungen sollte von einem Zufallszahlengenerator stammen, der für die Kryptografie entwickelt wurde. Die Initialisierung dieser Generatoren kann jedoch manchmal rechenintensiv oder langsam sein, so dass man sich bemühen sollte, sie nach Möglichkeit wiederzuverwenden.

Verwendung als Objektbezeichner

Nicht jede Anwendung erfordert Sicherheit. Die zufällige Zuweisung kann eine effiziente Möglichkeit für mehrere Entitäten sein, Identifikatoren in einem gemeinsam genutzten Raum ohne Koordination oder Partitionierung zu erzeugen. Die Koordinierung kann langsam sein, insbesondere in einer geclusterten oder verteilten Umgebung, und die Aufteilung eines Raums führt zu Problemen, wenn die Anteile der Entitäten zu klein oder zu groß sind.

Bezeichner, die ohne Maßnahmen zur Unvorhersehbarkeit generiert werden, sollten auf andere Weise geschützt werden, wenn ein Angreifer in der Lage sein könnte, sie einzusehen und zu manipulieren, wie es bei den meisten Webanwendungen der Fall ist. Es sollte ein separates Autorisierungssystem geben, das Objekte schützt, deren Bezeichner von einem Angreifer ohne Zugriffserlaubnis erraten werden können.

Es muss auch darauf geachtet werden, dass die Kennungen lang genug sind, um angesichts der zu erwartenden Gesamtzahl der Kennungen Kollisionen unwahrscheinlich zu machen. Dies wird als "Geburtstagsparadoxon" bezeichnet. Die Wahrscheinlichkeit eines Zusammenstoßes, p ist ungefähr n 2 /(2q x ), wobei n ist die Anzahl der tatsächlich erzeugten Identifikatoren, q die Anzahl der unterschiedlichen Symbole im Alphabet ist, und x ist die Länge der Identifikatoren. Dies sollte eine sehr kleine Zahl sein, etwa 2 50 oder weniger.

Daraus ergibt sich, dass die Wahrscheinlichkeit einer Kollision zwischen 500k 15-Zeichen-Kennungen etwa 2 % beträgt. 52 was wahrscheinlich unwahrscheinlicher ist als unentdeckte Fehler durch kosmische Strahlung usw.

Vergleich mit UUIDs

Gemäß ihrer Spezifikation, UUIDs nicht darauf ausgelegt sind, unberechenbar zu sein, und sollte nicht als Sitzungsbezeichner verwendet werden.

UUIDs in ihrem Standardformat benötigen viel Platz: 36 Zeichen für nur 122 Bits Entropie. (Nicht alle Bits einer "zufälligen" UUID werden nach dem Zufallsprinzip ausgewählt.) Eine zufällig ausgewählte alphanumerische Zeichenfolge bietet mehr Entropie in nur 21 Zeichen.

UUIDs sind nicht flexibel; sie haben eine standardisierte Struktur und ein standardisiertes Layout. Dies ist sowohl ihr größter Vorteil als auch ihre größte Schwäche. Bei der Zusammenarbeit mit einer externen Partei kann die Standardisierung, die UUIDs bieten, hilfreich sein. Für den rein internen Gebrauch können sie jedoch ineffizient sein.

6 Stimmen

Wenn Sie Leerzeichen benötigen, können Sie Folgendes anbringen .replaceAll("\\d", " "); auf das Ende des return new BigInteger(130, random).toString(32); Zeile, um einen Regex-Tausch vorzunehmen. Alle Ziffern werden durch Leerzeichen ersetzt. Funktioniert bei mir hervorragend: Ich verwende dies als Ersatz für ein Front-End-Lorem-Ipsum

4 Stimmen

@weisjohn Das ist eine gute Idee. Sie können etwas Ähnliches mit der zweiten Methode machen, indem Sie die Ziffern aus symbols Sie können die durchschnittliche "Wortlänge" steuern, indem Sie die Anzahl der Leerzeichen in den Symbolen ändern (mehr Vorkommen für kürzere Wörter). Für eine wirklich ausgefallene Fake-Text-Lösung können Sie eine Markov-Kette verwenden!

4 Stimmen

Diese Kennungen werden nach dem Zufallsprinzip aus einem Bereich einer bestimmten Größe ausgewählt. Sie können 1 Zeichen lang sein. Wenn Sie eine feste Länge wünschen, können Sie die zweite Lösung verwenden, mit einer SecureRandom Instanz, die der random variabel.

895voto

Steve McLeod Punkte 50514

Java bietet eine Möglichkeit, dies direkt zu tun. Wenn Sie die Bindestriche nicht wollen, lassen sie sich leicht entfernen. Verwenden Sie einfach 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;
    }
}

Ausgabe

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

36 Stimmen

Beachten Sie, dass diese Lösung nur eine zufällige Zeichenfolge mit hexadezimalen Zeichen erzeugt. Das kann in manchen Fällen in Ordnung sein.

6 Stimmen

Die Klasse UUID ist nützlich. Allerdings sind sie nicht so kompakt wie die von meinen Antworten erzeugten Bezeichner. Das kann zum Beispiel in URLs ein Problem sein. Das hängt von Ihren Bedürfnissen ab.

6 Stimmen

@Ruggs - Das Ziel ist alphanumerische Zeichenfolgen. Wie passt die Ausweitung der Ausgabe auf alle möglichen Bytes dazu?

637voto

maxp Punkte 5224
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();
}

72 Stimmen

+1, die einfachste Lösung zur Erzeugung einer zufälligen Zeichenkette mit bestimmter Länge (abgesehen von der Verwendung von RandomStringUtils aus Commons Lang).

15 Stimmen

Erwägen Sie die Verwendung von SecureRandom anstelle der Random Klasse. Wenn Passwörter auf einem Server generiert werden, kann dieser für Timing-Angriffe anfällig sein.

10 Stimmen

Ich würde auch Kleinbuchstaben hinzufügen: AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw‌​xyz"; und einige andere erlaubte Zeichen.

504voto

cmsherratt Punkte 2129

Wenn Sie gerne Apache-Klassen verwenden möchten, können Sie org.apache.commons.text.RandomStringGenerator ( Apache Commons Text ).

Beispiel:

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

Desde Apache Commons Lang 3.6, RandomStringUtils ist veraltet.

25 Stimmen

Hat gerade durchgeschaut genannte Klasse de Apache Commons Lang 3.3.1 Bibliothek - und sie verwendet nur java.util.Random zufällige Sequenzen zu liefern, so dass sie unsichere Abläufe .

16 Stimmen

Stellen Sie sicher, dass Sie SecureRandom verwenden, wenn Sie RandomStringUtils benutzen: public static java.lang.String random(int count, int start, int end, boolean letters, boolean numbers, @Nullable char[] chars, java.util.Random random)

0 Stimmen

NICHT VERWENDEN. Dies schafft unsichere Abläufe !

147voto

manish_s Punkte 5300

Sie können eine Apache Commons Bibliothek für diesen Zweck, RandomStringUtils :

RandomStringUtils.randomAlphanumeric(20).toUpperCase();

0 Stimmen

Garantiert diese Funktion eindeutige Ergebnisse, wenn sie zu verschiedenen Zeiten aufgerufen wird?

20 Stimmen

@kamil, ich habe mir den Quellcode von RandomStringUtils angesehen, und er verwendet eine Instanz von java.util.Random, die ohne Argumente instanziert wird. In der Dokumentation zu java.util.Random steht, dass die aktuelle Systemzeit verwendet wird, wenn kein Seed angegeben wird. Das bedeutet, dass es nicht für Sitzungskennungen/Schlüssel verwendet werden kann, da ein Angreifer leicht vorhersagen kann, wie die generierten Sitzungskennungen zu einem bestimmten Zeitpunkt lauten.

45 Stimmen

@Inshallah : Sie haben das System (unnötigerweise) überdimensioniert. Ich stimme zwar zu, dass es die Zeit als Seed verwendet, aber der Angreifer muss Zugang zu den folgenden Daten haben, um tatsächlich zu bekommen, was er will 1. Zeit auf die Millisekunde genau, wann der Code gestartet wurde 2. Anzahl der bisher erfolgten Aufrufe 3. Atomarität für seinen eigenen Aufruf (so dass die Anzahl der bisherigen Aufrufe gleich bleibt) Wenn Ihr Angreifer alle drei Dinge hat, dann haben Sie ein viel größeres Problem...

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X