Ich habe nach einem einfachen gesucht Java-Algorithmus , um eine pseudozufällige alphanumerische Zeichenfolge zu generieren. In meiner Situation würde es als eindeutige Sitzungs- / Schlüsselkennung verwendet, die "wahrscheinlich" über die 500K+
Generation hinweg eindeutig wäre (meine Anforderungen erfordern nicht wirklich viel ausgefeilteres).
Im Idealfall kann ich eine Länge angeben, die meinen Anforderungen an die Einzigartigkeit entspricht. Beispielsweise könnte eine generierte Zeichenfolge mit der Länge 12 ungefähr so aussehen "AEYGF7K0DM1X"
.
java
string
random
alphanumeric
Todd
quelle
quelle
Long.toHexString(Double.doubleToLongBits(Math.random()));
UUID.randomUUID().toString();
RandomStringUtils.randomAlphanumeric(12);
Antworten:
Algorithmus
Um eine zufällige Zeichenfolge zu generieren, verketten Sie Zeichen, die zufällig aus dem Satz akzeptabler Symbole gezogen wurden, bis die Zeichenfolge die gewünschte Länge erreicht hat.
Implementierung
Hier ist ein ziemlich einfacher und sehr flexibler Code zum Generieren von zufälligen Bezeichnern. Lesen Sie die folgenden Informationen, um wichtige Anwendungshinweise zu erhalten.
Anwendungsbeispiele
Erstellen Sie einen unsicheren Generator für 8-stellige Bezeichner:
Erstellen Sie einen sicheren Generator für Sitzungskennungen:
Erstellen Sie einen Generator mit einfach zu lesenden Codes zum Drucken. Die Zeichenfolgen sind länger als vollständige alphanumerische Zeichenfolgen, um die Verwendung weniger Symbole zu kompensieren:
Verwendung als Sitzungskennung
Das Generieren von Sitzungskennungen, die wahrscheinlich eindeutig sind, ist nicht gut genug, oder Sie können einfach einen einfachen Zähler verwenden. Angreifer entführen Sitzungen, wenn vorhersehbare Kennungen verwendet werden.
Es gibt Spannungen zwischen Länge und Sicherheit. Kürzere Kennungen sind leichter zu erraten, da weniger Möglichkeiten bestehen. Längere Kennungen verbrauchen jedoch mehr Speicher und Bandbreite. Ein größerer Satz von Symbolen hilft, kann jedoch zu Codierungsproblemen führen, wenn Bezeichner in URLs enthalten sind oder von Hand neu eingegeben werden.
Die zugrunde liegende Quelle für Zufälligkeit oder Entropie für Sitzungskennungen sollte ein Zufallszahlengenerator sein, der für die Kryptographie entwickelt wurde. Das Initialisieren dieser Generatoren kann jedoch manchmal rechenintensiv oder langsam sein. Daher sollten Anstrengungen unternommen werden, um sie nach Möglichkeit wiederzuverwenden.
Verwendung als Objektkennungen
Nicht jede Anwendung erfordert Sicherheit. Die zufällige Zuweisung kann eine effiziente Möglichkeit für mehrere Entitäten sein, Bezeichner in einem gemeinsam genutzten Bereich ohne Koordination oder Partitionierung zu generieren. Die Koordination kann langsam sein, insbesondere in einer Cluster- oder verteilten Umgebung, und die Aufteilung eines Bereichs verursacht Probleme, wenn Entitäten zu kleine oder zu große Freigaben erhalten.
Bezeichner, die generiert werden, ohne Maßnahmen zu ergreifen, um sie unvorhersehbar zu machen, sollten auf andere Weise geschützt werden, wenn ein Angreifer sie möglicherweise anzeigen und bearbeiten kann, wie dies in den meisten Webanwendungen der Fall ist. Es sollte ein separates Autorisierungssystem geben, das Objekte schützt, deren Kennung von einem Angreifer ohne Zugriffsberechtigung erraten werden kann.
Es muss auch darauf geachtet werden, Kennungen zu verwenden, die lang genug sind, um Kollisionen angesichts der erwarteten Gesamtzahl der Kennungen unwahrscheinlich zu machen. Dies wird als "Geburtstagsparadoxon" bezeichnet. Die Wahrscheinlichkeit einer Kollision p beträgt ungefähr n 2 / (2q x ), wobei n die Anzahl der tatsächlich erzeugten Bezeichner ist, q die Anzahl der unterschiedlichen Symbole im Alphabet ist und x die Länge der Bezeichner ist. Dies sollte eine sehr kleine Zahl sein, wie 2 - 50 oder weniger.
Arbeiten dieser heraus zeigt , dass die Wahrscheinlichkeit einer Kollision zwischen 500k 15 Zeichen Bezeichner ist etwa 2 -52 , was wahrscheinlich weniger wahrscheinlich ist als unentdeckte Fehler durch kosmische Strahlung usw.
Vergleich mit UUIDs
Entsprechend ihrer Spezifikation sind UUIDs nicht unvorhersehbar und sollten nicht als Sitzungskennungen verwendet werden.
UUIDs in ihrem Standardformat nehmen viel Platz ein: 36 Zeichen für nur 122 Entropiebits. (Nicht alle Bits einer "zufälligen" UUID werden zufällig ausgewählt.) Eine zufällig ausgewählte alphanumerische Zeichenfolge enthält mehr Entropie in nur 21 Zeichen.
UUIDs sind nicht flexibel. Sie haben eine standardisierte Struktur und ein standardisiertes Layout. Dies ist ihre Haupttugend sowie ihre Hauptschwäche. Bei der Zusammenarbeit mit einer externen Partei kann die von UUIDs angebotene Standardisierung hilfreich sein. Für den rein internen Gebrauch können sie ineffizient sein.
quelle
.replaceAll("\\d", " ");
Ende derreturn new BigInteger(130, random).toString(32);
Zeile einen Regex-Tausch durchführen. Es ersetzt alle Ziffern durch Leerzeichen. Funktioniert hervorragend für mich: Ich verwende dies als Ersatz für ein Front-End Lorem Ipsumsymbols
und stattdessen ein Leerzeichen verwenden. Sie können die durchschnittliche "Wort" -Länge steuern, indem Sie die Anzahl der Leerzeichen in Symbolen ändern (mehr Vorkommen für kürzere Wörter). Für eine wirklich übertriebene Lösung für gefälschten Text können Sie eine Markov-Kette verwenden!SecureRandom
derrandom
Variablen eine Instanz zugewiesen ist.Java bietet eine Möglichkeit, dies direkt zu tun. Wenn Sie die Striche nicht möchten, können Sie sie leicht entfernen. Benutz einfach
uuid.replace("-", "")
Ausgabe:
quelle
UUID.randomUUID().toString().replaceAll("-", "");
macht die Zeichenfolge wie gewünscht alphanumerisch.quelle
SecureRandom
anstelle derRandom
Klasse. Wenn Kennwörter auf einem Server generiert werden, ist dies möglicherweise anfällig für Timing-Angriffe.AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
und einige andere erlaubte Zeichen.static Random rnd = new Random();
in die Methode einbauen?Random
Objekt bei jedem Methodenaufruf zu erstellen ? Das glaube ich nicht.Wenn Sie gerne Apache-Klassen verwenden, können Sie
org.apache.commons.text.RandomStringGenerator
(Commons-Text) verwenden.Beispiel:
Da commons-lang 3.6,
RandomStringUtils
ist veraltet.quelle
Apache Commons Lang 3.3.1
Bibliotheken durchgesehen - und es wird nur verwendetjava.util.Random
, um zufällige Sequenzen bereitzustellen, so dass es unsichere Sequenzen erzeugt .public static java.lang.String random(int count, int start, int end, boolean letters, boolean numbers, @Nullable char[] chars, java.util.Random random)
Sie können die Apache-Bibliothek dafür verwenden: RandomStringUtils
quelle
compile 'commons-lang:commons-lang:2.6'
SecureRandom
und du bist gut.In einer Zeile:
quelle
AEYGF7K0DM1X
das nicht hexadezimal ist. Es macht mir Sorgen, wie oft Menschen alphanumerisch mit hexadezimal verwechseln. Sie sind nicht dasselbe.Math.random()
ein produziertdouble
zwischen 0 und 1, so dass der Exponenten Teil meist ungenutzt ist. Verwenden Sierandom.nextLong
für einen zufälligenlong
anstelle dieses hässlichen Hacks.Dies ist ohne externe Bibliotheken leicht zu erreichen.
1. Kryptografische Pseudozufallsdatengenerierung
Zuerst benötigen Sie ein kryptografisches PRNG. Java hat
SecureRandom
dafür und verwendet normalerweise die beste Entropiequelle auf der Maschine (z/dev/random
. B. ). Lesen Sie hier mehr.Hinweis:
SecureRandom
Dies ist die langsamste, aber sicherste Methode in Java, um zufällige Bytes zu generieren. Ich empfehle jedoch, die Leistung hier NICHT zu berücksichtigen, da dies normalerweise keine wirklichen Auswirkungen auf Ihre Anwendung hat, es sei denn, Sie müssen Millionen von Token pro Sekunde generieren.2. Erforderlicher Platz für mögliche Werte
Als nächstes müssen Sie entscheiden, "wie einzigartig" Ihr Token sein muss. Der ganze und einzige Punkt bei der Betrachtung der Entropie besteht darin, sicherzustellen, dass das System Brute-Force-Angriffen widerstehen kann: Der Raum möglicher Werte muss so groß sein, dass jeder Angreifer nur einen vernachlässigbaren Anteil der Werte in nicht lächerlicher Zeit versuchen kann 1 . Eindeutige Bezeichner wie zufällig
UUID
haben eine Entropie von 122 Bit (dh 2 ^ 122 = 5,3 x 10 ^ 36) - die Wahrscheinlichkeit einer Kollision ist "* (...), damit eine Eins-zu-eine-Milliarde-Chance auf Duplizierung besteht, eine Version von 103 Billionen 4 UUIDs müssen 2 " generiert werden . Wir werden 128 Bit wählen, da es genau in 16 Bytes passt und als gesehen wird sehr ausreichend angesehen wirdUm für praktisch alle, aber extremsten Anwendungsfälle einzigartig zu sein, müssen Sie nicht über Duplikate nachdenken. Hier ist eine einfache Vergleichstabelle der Entropie einschließlich einer einfachen Analyse des Geburtstagsproblems .Für einfache Anforderungen mag eine Länge von 8 oder 12 Bytes ausreichen, aber mit 16 Bytes sind Sie auf der "sicheren Seite".
Und das war's auch schon. Als letztes müssen Sie über die Codierung nachdenken, damit sie als druckbarer Text dargestellt werden kann (lesen Sie, a
String
).3. Binär-Text-Codierung
Typische Codierungen umfassen:
Base64
Jedes Zeichen codiert 6 Bit und verursacht einen Overhead von 33%. Glücklicherweise gibt es Standardimplementierungen in Java 8+ und Android . Mit älterem Java können Sie eine der zahlreichen Bibliotheken von Drittanbietern verwenden . Wenn Sie möchten, dass Ihre Token url-sicher sind, verwenden Sie die url-sichere Version von RFC4648 (die normalerweise von den meisten Implementierungen unterstützt wird). Beispiel für die Codierung von 16 Bytes mit Auffüllung:XfJhfv3C0P6ag7y9VQxSbw==
Base32
Jedes Zeichen codiert 5 Bit und verursacht einen Overhead von 40%. Dies wird es verwendenA-Z
und2-7
es einigermaßen platzsparend machen, während die Groß- und Kleinschreibung nicht berücksichtigt wird. Es gibt keine Standardimplementierung im JDK . Beispiel für die Codierung von 16 Bytes ohne Auffüllen:WUPIL5DQTZGMF4D3NX5L7LNFOY
Base16
(hex) Jedes Zeichen codiert 4 Bit, wobei 2 Zeichen pro Byte erforderlich sind (dh 16 Byte erzeugen eine Zeichenfolge mit der Länge 32). Daher ist hex weniger platzsparend alsBase32
, ist aber in den meisten Fällen sicher zu verwenden (URL), da es nur0-9
undA
zu verwendetF
. Beispiel für die Codierung von 16 Bytes :4fa3dd0f57cb3bf331441ed285b27735
. Eine SO-Diskussion zum Konvertieren in Hex finden Sie hier.Zusätzliche Codierungen wie Base85 und die exotische Base122 existieren mit besserer / schlechterer Raumeffizienz . Sie können Ihre eigene Codierung erstellen (was im Grunde die meisten Antworten in diesem Thread tun), aber ich würde davon abraten, wenn Sie keine sehr spezifischen Anforderungen haben. Siehe mehr Kodierungsschemata in Wikipedia - Artikel.
4. Zusammenfassung und Beispiel
SecureRandom
hex
oderbase32
wenn Sie es alphanumerisch benötigen)Tu es nicht
Beispiel: Hex Token Generator
Beispiel: Base64 Token Generator (Url Safe)
Beispiel: Java CLI Tool
Wenn Sie ein gebrauchsfertiges CLI-Tool benötigen, können Sie Würfel verwenden: https://github.com/patrickfav/dice
Beispiel: Verwandte Probleme - Schützen Sie Ihre aktuellen IDs
Wenn Sie bereits eine ID haben, die Sie verwenden können (z. B. eine synthetische ID
long
in Ihrer Entität), den internen Wert jedoch nicht veröffentlichen möchten , können Sie diese Bibliothek verwenden, um sie zu verschlüsseln und zu verschleiern: https://github.com/patrickfav / id-maskquelle
BigInteger
s mithilfe eines Konstruktorparameters verhindern:BigInteger(1, token)
anstelle vonBigInteger(token)
.import java.security.SecureRandom;
undimport java.math.BigInteger;
werden benötigt, damit das Beispiel funktioniert, aber es funktioniert großartig!new SecureRandom()
verwendet/dev/urandom
Die Verwendung von Dollar sollte einfach sein als:
es gibt so etwas aus:
quelle
Hier ist es in Java:
Hier ist ein Probelauf:
quelle
Random#nextInt
odernextLong
. Wechseln SieSecureRandom
bei Bedarf zu.Überraschenderweise hat es hier niemand vorgeschlagen, aber:
Einfach.
Dies hat den Vorteil, dass UUIDs schön lang sind und garantiert kaum kollidieren können.
Wikipedia hat eine gute Erklärung dafür:
http://en.wikipedia.org/wiki/Universally_unique_identifier#Random_UUID_probability_of_duplicates
Die ersten 4 Bits sind der Versionstyp und 2 für die Variante, sodass Sie 122 zufällige Bits erhalten. Wenn Sie möchten , können Sie vom Ende abschneiden, um die Größe der UUID zu verringern. Es wird nicht empfohlen, aber Sie haben immer noch eine Menge Zufälligkeiten, genug für Ihre 500.000 Datensätze.
quelle
Eine kurze und einfache Lösung, die jedoch nur Kleinbuchstaben und Zahlen verwendet:
Die Größe beträgt ungefähr 12 Stellen bis zur Basis 36 und kann auf diese Weise nicht weiter verbessert werden. Natürlich können Sie mehrere Instanzen anhängen.
quelle
Long.toString(Math.abs(r.nextLong()), 36);
abs
wird gelöst, indem ein bitweiser Operator verwendet wird, um das höchstwertige Bit zu löschen. Dies funktioniert für alle Werte.<< 1 >>> 1
.Eine Alternative in Java 8 ist:
quelle
Die Verwendung von UUIDs ist unsicher, da Teile der UUID überhaupt nicht zufällig sind. Die Prozedur von @erickson ist sehr ordentlich, erstellt jedoch keine Zeichenfolgen gleicher Länge. Das folgende Snippet sollte ausreichen:
Warum wählen
length*5
. Nehmen wir den einfachen Fall einer zufälligen Zeichenfolge der Länge 1 an, also eines zufälligen Zeichens. Um ein zufälliges Zeichen zu erhalten, das alle Ziffern 0-9 und die Zeichen az enthält, benötigen wir eine Zufallszahl zwischen 0 und 35, um eines von jedem Zeichen zu erhalten.BigInteger
stellt einen Konstruktor zum Generieren einer Zufallszahl bereit, die gleichmäßig über die Bereichsnummer verteilt ist. Das letzte Problem: Wenn wir eine Zeichenfolge mit einer bestimmten Länge möchten, kann zufällig eine kleine Zahl generiert werden, sodass die Länge nicht eingehalten wird. Daher müssen wir die Zeichenfolge auf die erforderliche Länge vor Nullen auffüllen.0 to (2^numBits - 1)
. Leider ist 35 keine Nummer, die von 2 ^ numBits - 1 empfangen werden kann. Wir haben also zwei Möglichkeiten: Entweder mit2^5-1=31
oder2^6-1=63
. Wenn wir uns entscheiden2^6
würden, würden wir viele "unnötige" / "längere" Zahlen bekommen. Daher2^5
ist die bessere Option, auch wenn wir 4 Zeichen (wz) verlieren. Um jetzt einen String einer bestimmten Länge zu generieren, können wir einfach a verwenden2^(length*numBits)-1
quelle
quelle
Also fügt man einfach das Passwort in die Zeichenfolge ein und ... ja, funktioniert gut, check it out ... sehr einfach. ich schrieb es
quelle
+ 0
das oft hinzu? Warum teilen Sie die Deklaration von Spot und Initialisierung auf? Was ist der Vorteil der Indizes 1,2,3,4 anstelle von 0,1,2,3? Am wichtigsten: Sie haben einen zufälligen Wert genommen und mit dem 4-fachen eines neuen Wertes verglichen, der immer nicht übereinstimmen könnte, ohne mehr Zufälligkeit zu erlangen. Aber zögern Sie nicht, einen Rollback durchzuführen.Ich habe diese Lösung gefunden, die eine zufällige hexadezimal codierte Zeichenfolge generiert. Der bereitgestellte Unit-Test scheint meinem primären Anwendungsfall standzuhalten. Es ist jedoch etwas komplexer als einige der anderen Antworten.
quelle
Ändern Sie die Zeichenfolgen gemäß Ihren Anforderungen.
String ist unveränderlich. Hier
StringBuilder.append
ist effizienter als die Verkettung von Zeichenfolgen.quelle
Random
Instanz in jeder Iteration der Schleife ist ineffizient.quelle
quelle
Mag keine dieser Antworten in Bezug auf "einfache" Lösung wirklich: S.
Ich würde mich für ein einfaches;), reines Java, einen Liner entscheiden (Entropie basiert auf zufälliger Stringlänge und dem angegebenen Zeichensatz):
oder (etwas lesbarer alter Weg)
Andererseits können Sie auch eine UUID verwenden, die eine ziemlich gute Entropie aufweist ( https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions ):
Ich hoffe, das hilft.
quelle
Sie erwähnen "einfach", aber nur für den Fall, dass jemand anderes nach etwas sucht, das strengere Sicherheitsanforderungen erfüllt, sollten Sie sich jpwgen ansehen . jpwgen ist in Unix nach pwgen modelliert und sehr konfigurierbar.
quelle
Sie können die UUID-Klasse mit ihrer getLeastSignificantBits () -Nachricht verwenden, um 64-Bit-Zufallsdaten abzurufen und sie dann in eine Radix 36-Zahl (dh eine Zeichenfolge bestehend aus 0-9, AZ) zu konvertieren:
Dies ergibt einen String mit einer Länge von bis zu 13 Zeichen. Wir verwenden Math.abs (), um sicherzustellen, dass sich kein Minuszeichen einschleicht.
quelle
random.nextLong()
? Oder sogarDouble.doubleToLongBits(Math.random())
?Sie können den folgenden Code verwenden, wenn Ihr Kennwort obligatorisch alphabetische Sonderzeichen enthält:
quelle
Hier ist der einzeilige Code von AbacusUtil
Zufällig bedeutet nicht, dass es eindeutig sein muss. um eindeutige Zeichenfolgen zu erhalten, verwenden Sie:
quelle
Hier ist es eine Scala-Lösung:
quelle
Mit der Apache-Bibliothek kann dies in einer Zeile erfolgen
Hier ist das Dokument http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/RandomStringUtils.html
quelle
quelle
Ich denke, dies ist die kleinste Lösung oder fast eine der kleinsten:
Der Code funktioniert einwandfrei. Wenn Sie diese Methode verwenden, empfehle ich Ihnen, mehr als 10 Zeichen zu verwenden. Die Kollision erfolgt bei 5 Zeichen / 30362 Iterationen. Dies dauerte 9 Sekunden.
quelle
quelle
length
stattchars.length
in der for-Schleife sein:for (int i = 0; i < length; i++)
quelle