Beachten Sie, dass Sie KEINE auf der RandomKlasse basierende Methode verwenden sollten , um Kennwörter zu generieren. Die Aussaat Randomhat eine sehr geringe Entropie, daher ist sie nicht wirklich sicher. Verwenden Sie ein kryptografisches PRNG für Kennwörter.
CodesInChaos
2
Es wäre schön, die Sprachlokalisierung in diese Frage aufzunehmen. Vor allem, wenn Ihre GUI für Chinesisch oder Bulgarisch sorgen muss!
Peter Jamsmenson
15
Etwas mit so vielen positiven Stimmen und so vielen hochwertigen Antworten verdient es nicht, als geschlossen markiert zu werden. Ich stimme dafür, dass es wiedereröffnet wird.
John Coleman
Antworten:
1684
Ich habe gehört, dass LINQ das neue Schwarz ist. Hier ist mein Versuch, LINQ zu verwenden:
privatestaticRandom random =newRandom();publicstaticstringRandomString(int length){conststring chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";returnnewstring(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());}
(Hinweis: Die Verwendung der RandomKlasse macht dies für sicherheitsrelevante Zwecke wie das Erstellen von Kennwörtern oder Token ungeeignet . Verwenden Sie die RNGCryptoServiceProviderKlasse, wenn Sie einen starken Zufallszahlengenerator benötigen.)
@Alex: Ich habe ein paar schnelle Tests durchgeführt und es scheint ziemlich linear zu skalieren, wenn längere Zeichenfolgen generiert werden (solange tatsächlich genügend Speicher verfügbar ist). Trotzdem war Dan Rigbys Antwort in jedem Test fast doppelt so schnell wie diese.
LukeH
6
Gut. Wenn Ihr Kriterium ist, dass es linq verwendet und dass es eine miese Code-Erzählung hat, dann sind es definitiv die Knie der Biene. Sowohl die Codeerzählung als auch der tatsächliche Ausführungspfad sind eher ineffizient und indirekt. Versteh mich nicht falsch, ich bin ein riesiger Code-Hipster (ich liebe Python), aber das ist so ziemlich eine Rube Goldberg-Maschine.
Eremzeit
5
Während dies die Frage technisch beantwortet, ist die Ausgabe sehr irreführend. Das Generieren von 8 zufälligen Zeichen klingt so, als ob es sehr viele Ergebnisse geben kann, während dies bestenfalls 2 Milliarden verschiedene Ergebnisse liefert. Und in der Praxis noch weniger. Sie sollten auch eine BIG FAT-Warnung hinzufügen, um diese nicht für sicherheitsrelevante Zwecke zu verwenden.
CodesInChaos
41
@xaisoft: Kleinbuchstaben bleiben als Übung für den Leser.
dtb
15
Die folgende Zeile ist speichereffizienter (und damit zeitsparender) als die angegebenereturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tyson Williams
376
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";var stringChars =newchar[8];var random =newRandom();for(int i =0; i < stringChars.Length; i++){
stringChars[i]= chars[random.Next(chars.Length)];}var finalString =newString(stringChars);
Nicht so elegant wie die Linq-Lösung.
(Hinweis: Die Verwendung der RandomKlasse macht dies für sicherheitsrelevante Zwecke wie das Erstellen von Kennwörtern oder Token ungeeignet . Verwenden Sie die RNGCryptoServiceProviderKlasse, wenn Sie einen starken Zufallszahlengenerator benötigen.)
@Alex: Dies ist nicht die absolut schnellste Antwort, aber es ist die schnellste "echte" Antwort (dh von denen, die die Kontrolle über die verwendeten Zeichen und die Länge der Zeichenfolge ermöglichen).
LukeH
2
@Alex: Die GetRandomFileNameLösung von Adam Porad ist schneller, erlaubt jedoch keine Kontrolle über die verwendeten Zeichen und die maximal mögliche Länge beträgt 11 Zeichen. Douglas ' GuidLösung ist blitzschnell, aber die Zeichen sind auf A-F0-9 beschränkt und die maximal mögliche Länge beträgt 32 Zeichen.
LukeH
1
@Adam: Ja, Sie könnten das Ergebnis mehrerer Aufrufe zusammenfassen, GetRandomFileNameaber dann (a) würden Sie Ihren Leistungsvorteil verlieren und (b) Ihr Code würde komplizierter werden.
LukeH
2
@xaisoft erstellt Ihre Instanz des Random () -Objekts außerhalb Ihrer Schleife. Wenn Sie in einem kurzen Intervall viele Instanzen von Random () erstellen, gibt der Aufruf von .Next () den gleichen Wert zurück wie Random () einen zeitbasierten Startwert verwendet.
Dan Rigby
2
@xaisoft Verwenden Sie diese Antwort nicht für sicherheitskritische Elemente wie Kennwörter. System.Randomist nicht für die Sicherheit geeignet.
CodesInChaos
333
AKTUALISIERT basierend auf Kommentaren. Die ursprüngliche Implementierung erzeugte in ~ 1,95% der Fälle und die verbleibenden Zeichen in ~ 1,56% der Fälle. Das Update generiert in ~ 1,61% der Fälle alle Zeichen.
FRAMEWORK SUPPORT - .NET Core 3 (und zukünftige Plattformen, die .NET Standard 2.1 oder höher unterstützen) bietet eine kryptografisch fundierte Methode RandomNumberGenerator.GetInt32 () , um eine zufällige Ganzzahl innerhalb eines gewünschten Bereichs zu generieren.
Im Gegensatz zu einigen der vorgestellten Alternativen ist diese kryptografisch fundiert .
using System;
using System.Security.Cryptography;
using System.Text;
namespace UniqueKey{publicclassKeyGenerator{internalstaticreadonlychar[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();publicstaticstringGetUniqueKey(int size){byte[] data =newbyte[4*size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);for(int i =0; i < size; i++){var rnd =BitConverter.ToUInt32(data, i *4);var idx = rnd % chars.Length;
result.Append(chars[idx]);}return result.ToString();}publicstaticstringGetUniqueKeyOriginal_BIASED(int size){char[] chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();byte[] data =newbyte[size];
using (RNGCryptoServiceProvider crypto =newRNGCryptoServiceProvider()){
crypto.GetBytes(data);}StringBuilder result =newStringBuilder(size);foreach(byte b in data){
result.Append(chars[b %(chars.Length)]);}return result.ToString();}}}
Basierend auf einer Diskussion der Alternativen hier und aktualisiert / modifiziert basierend auf den Kommentaren unten.
Hier ist ein kleines Testkabel, das die Verteilung der Zeichen in der alten und aktualisierten Ausgabe demonstriert. Eine ausführliche Beschreibung der Analyse der Zufälligkeit finden Sie unter random.org.
using System;
using System.Collections.Generic;
using System.Linq;
using UniqueKey;
namespace CryptoRNGDemo{classProgram{constint REPETITIONS =1000000;constint KEY_SIZE =32;staticvoidMain(string[] args){Console.WriteLine("Original BIASED implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKeyOriginal_BIASED);Console.WriteLine("Updated implementation");PerformTest(REPETITIONS, KEY_SIZE,KeyGenerator.GetUniqueKey);Console.ReadKey();}staticvoidPerformTest(int repetitions,int keySize,Func<int,string> generator){Dictionary<char,int> counts =newDictionary<char,int>();foreach(var ch inUniqueKey.KeyGenerator.chars) counts.Add(ch,0);for(int i =0; i < REPETITIONS; i++){var key = generator(KEY_SIZE);foreach(var ch in key) counts[ch]++;}int totalChars = counts.Values.Sum();foreach(var ch inUniqueKey.KeyGenerator.chars){Console.WriteLine($"{ch}: {(100.0 * counts[ch] / totalChars).ToString("#.000")}%");}}}}
Dies scheint mir die richtige Herangehensweise zu sein - zufällige Passwörter, Salze, Entropie usw. sollten nicht mit Random () generiert werden, das auf Geschwindigkeit optimiert ist und reproduzierbare Zahlenfolgen generiert. RNGCryptoServiceProvider.GetNonZeroBytes () erzeugt dagegen wilde Folgen von Zahlen, die NICHT reproduzierbar sind.
mindplay.dk
25
Die Buchstaben sind leicht voreingenommen (255% 62! = 0). Trotz dieses kleinen Fehlers ist es hier bei weitem die beste Lösung.
CodesInChaos
13
Beachten Sie, dass dies nicht sinnvoll ist, wenn Sie eine kryptostarke, unvoreingenommene Zufälligkeit wünschen. (Und wenn Sie das nicht wollen, warum dann überhaupt verwenden RNGCSP?) Die Verwendung von Mod zum Indizieren in das charsArray bedeutet, dass Sie eine voreingenommene Ausgabe erhalten, es sei denn, chars.Lengthes handelt sich um einen Divisor von 256.
LukeH
15
Eine Möglichkeit, die Vorspannung stark zu reduzieren, besteht darin, 4*maxSizezufällige Bytes anzufordern und dann zu verwenden (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length. Ich würde auch GetBytesanstelle von verwenden GetNonZeroBytes. Und schließlich können Sie den ersten Anruf an entfernen GetNonZeroBytes. Sie verwenden das Ergebnis nicht.
CodesInChaos
14
Unterhaltsame Tatsache: AZ az 0-9 besteht aus 62 Zeichen. Die Leute weisen auf Buchstabenbias hin, weil 256% 62! = 0. Die Video-IDs von YouTube sind AZ az 0-9 sowie "-" und "_", wodurch 64 mögliche Zeichen erzeugt werden, die sich gleichmäßig in 256 teilen. Zufall? Ich denke nicht! :)
qJake
200
Lösung 1 - größter Bereich mit der flexibelsten Länge
Diese Lösung hat mehr Reichweite als die Verwendung einer GUID, da eine GUID einige feste Bits hat, die immer gleich und daher nicht zufällig sind. Beispielsweise ist das hexadezimale 13-Zeichen immer "4" - zumindest in einer GUID der Version 6.
Mit dieser Lösung können Sie auch eine Zeichenfolge beliebiger Länge generieren.
Lösung 2 - Eine Codezeile - gut für bis zu 22 Zeichen
Sie können keine Zeichenfolgen generieren, solange Lösung 1 vorhanden ist und die Zeichenfolge aufgrund fester Bits in den GUIDs nicht denselben Bereich haben. In vielen Fällen reicht dies jedoch aus.
Lösung 3 - Etwas weniger Code
Guid.NewGuid().ToString("n").Substring(0,8);
Meistens hier für historische Zwecke. Es wird etwas weniger Code verwendet, was jedoch die Kosten für eine geringere Reichweite mit sich bringt. Da Hex anstelle von base64 verwendet wird, sind im Vergleich zu den anderen Lösungen mehr Zeichen erforderlich, um denselben Bereich darzustellen.
Dies bedeutet eine höhere Kollisionswahrscheinlichkeit. Durch Testen mit 100.000 Iterationen von 8 Zeichenfolgen wurde ein Duplikat generiert.
Sie haben tatsächlich ein Duplikat erstellt? Überraschend bei 5.316.911.983.139.663.491.615.228.241.121.400.000 möglichen Kombinationen von GUIDs.
Alex
73
@Alex: Er verkürzt die GUID auf 8 Zeichen, daher ist die Wahrscheinlichkeit von Kollisionen viel höher als die von GUIDs.
dtb
23
Niemand außer Nerds kann das schätzen :) Ja, Sie haben absolut Recht, das Limit von 8 Zeichen macht einen Unterschied.
Alex
31
Guid.NewGuid (). ToString ("n") hält die Striche fern, es ist kein Aufruf von Replace () erforderlich. Es sollte jedoch erwähnt werden, dass die GUIDs nur 0-9 und AF sind. Die Anzahl der Kombinationen ist "gut genug", aber bei weitem nicht annähernd das, was eine echte alphanumerische Zufallszeichenfolge zulässt. Die Wahrscheinlichkeit einer Kollision beträgt 1: 4,294,967,296 - das gleiche wie bei einer zufälligen 32-Bit-Ganzzahl.
richardtallent
32
1) GUIDs sind eindeutig und nicht zufällig. Während aktuelle Windows-Versionen V4-GUIDs generieren, die tatsächlich zufällig sind, ist dies nicht garantiert. Zum Beispiel verwendeten ältere Windows-Versionen V1-GUIDs, bei denen dies fehlschlagen könnte. 2) Die Verwendung von Hex-Zeichen verringert die Qualität der zufälligen Zeichenfolge erheblich. Von 47 bis 32 Bit. 3) Menschen unterschätzen die Kollisionswahrscheinlichkeit, da sie sie für einzelne Paare angeben. Wenn Sie 100.000 32-Bit-Werte generieren, haben Sie wahrscheinlich eine Kollision zwischen ihnen. Siehe Geburtstagsproblem.
CodesInChaos
72
Hier ist ein Beispiel, das ich aus dem Beispiel von Sam Allen bei gestohlen habe Dot Net Perls
Wenn Sie nur 8 Zeichen benötigen, verwenden Sie Path.GetRandomFileName () im System.IO-Namespace. Sam sagt, dass die Verwendung der "Path.GetRandomFileName-Methode hier manchmal überlegen ist, da sie RNGCryptoServiceProvider für eine bessere Zufälligkeit verwendet. Sie ist jedoch auf 11 zufällige Zeichen beschränkt."
GetRandomFileName gibt immer eine 12-stellige Zeichenfolge mit einem Punkt am 9. Zeichen zurück. Sie müssen also den Punkt entfernen (da dies nicht zufällig ist) und dann 8 Zeichen aus der Zeichenfolge entfernen. Eigentlich könnte man einfach die ersten 8 Zeichen nehmen und sich keine Sorgen um den Zeitraum machen.
Das funktioniert gut. Ich habe 100.000 Iterationen durchlaufen und hatte nie einen doppelten Namen. Ich habe jedoch einige vulgäre Wörter gefunden (auf Englisch). Ich hätte nicht einmal daran gedacht, außer dass einer der ersten auf der Liste F *** enthielt. Nur ein Hinweis, wenn Sie dies für etwas verwenden, das der Benutzer sehen wird.
Techturtle
3
@techturtle Danke für die Warnung. Ich nehme an, es besteht ein Risiko für vulgäre Wörter bei jeder zufälligen Zeichenfolgengenerierung, bei der alle Buchstaben des Alphabets verwendet werden.
Adam Porad
nett und einfach, aber nicht gut für lange Saiten ...
stimme
Diese Methode scheint nur alphanumerische Zeichenfolgen in Kleinbuchstaben zurückzugeben.
Jaybro
2
Es gibt von Zeit zu Zeit vulgäre Worte, aber wenn Sie dies lange genug laufen lassen, schreibt es schließlich Shakespeare. (Nur ein paar Leben des Universums. :)
Slothario
38
Die Hauptziele meines Codes sind:
Die Verteilung der Zeichenfolgen ist nahezu gleichmäßig (kleinere Abweichungen sind nicht wichtig, solange sie klein sind).
Es werden mehr als ein paar Milliarden Zeichenfolgen für jeden Argumentsatz ausgegeben. Das Generieren einer 8-Zeichenfolge (~ 47 Bit Entropie) ist bedeutungslos, wenn Ihr PRNG nur 2 Milliarden (31 Bit Entropie) verschiedene Werte generiert.
Es ist sicher, da ich erwarte, dass Leute dies für Passwörter oder andere Sicherheitstoken verwenden.
Die erste Eigenschaft wird erreicht, indem ein 64-Bit-Wert modulo der Alphabetgröße verwendet wird. Bei kleinen Alphabeten (wie den 62 Zeichen aus der Frage) führt dies zu einer vernachlässigbaren Verzerrung. Die zweite und dritte Eigenschaft werden durch Verwendung von RNGCryptoServiceProvideranstelle von erreicht System.Random.
using System;
using System.Security.Cryptography;publicstaticstringGetRandomAlphanumericString(int length){conststring alphanumericCharacters ="ABCDEFGHIJKLMNOPQRSTUVWXYZ"+"abcdefghijklmnopqrstuvwxyz"+"0123456789";returnGetRandomString(length, alphanumericCharacters);}publicstaticstringGetRandomString(int length,IEnumerable<char> characterSet){if(length <0)thrownewArgumentException("length must not be negative","length");if(length >int.MaxValue/8)// 250 million chars ought to be enough for anybodythrownewArgumentException("length is too big","length");if(characterSet ==null)thrownewArgumentNullException("characterSet");var characterArray = characterSet.Distinct().ToArray();if(characterArray.Length==0)thrownewArgumentException("characterSet must not be empty","characterSet");var bytes =newbyte[length *8];var result =newchar[length];
using (var cryptoProvider =newRNGCryptoServiceProvider()){
cryptoProvider.GetBytes(bytes);}for(int i =0; i < length; i++){ulongvalue=BitConverter.ToUInt64(bytes, i *8);
result[i]= characterArray[value%(uint)characterArray.Length];}returnnewstring(result);}
Es gibt keinen Schnittpunkt mit 64 x Z und Math.Pow (2, Y). Wenn Sie also größere Zahlen erstellen, wird die Verzerrung verringert, aber nicht beseitigt. Ich habe meine Antwort unten aktualisiert. Mein Ansatz war es, zufällige Eingaben zu verwerfen und durch einen anderen Wert zu ersetzen.
Todd
@Todd Ich weiß, dass es die Verzerrung nicht beseitigt, aber ich habe die Einfachheit dieser Lösung der Beseitigung einer praktisch irrelevanten Verzerrung vorgezogen.
CodesInChaos
Ich stimme zu, dass dies in den meisten Fällen wahrscheinlich praktisch irrelevant ist. Aber jetzt habe ich meine so aktualisiert, dass sie sowohl so schnell wie zufällig als auch etwas sicherer als Ihre ist. Alles Open Source für alle zum Teilen. Ja, ich habe viel zu viel Zeit damit verschwendet ...
Todd
Wenn wir einen RNG-Anbieter verwenden, haben wir dann eine Möglichkeit, theoretische Verzerrungen zu vermeiden? Ich bin mir nicht sicher ... Wenn Todd meint, wie er zusätzliche Zufallszahlen generiert (wenn wir uns in der Bias-Zone befinden), kann dies eine falsche Annahme sein. RNG hat eine nahezu lineare Verteilung aller generierten Werte im Durchschnitt. Dies bedeutet jedoch nicht, dass keine lokale Korrelation zwischen den generierten Bytes besteht. Ein zusätzliches Byte nur für die Vorspannungszone kann uns also immer noch eine gewisse Vorspannung geben, jedoch aus einem anderen Grund. Höchstwahrscheinlich wird diese Tendenz sehr gering sein. ABER in diesem Fall ist das Erhöhen der insgesamt erzeugten Bytes einfacher.
Maxim
1
@Maxim Sie können die Zurückweisung verwenden, um die Verzerrung vollständig zu beseitigen (vorausgesetzt, der zugrunde liegende Generator ist vollkommen zufällig). Im Gegenzug kann der Code beliebig lang sein (mit exponentiell geringer Wahrscheinlichkeit).
Wenn Sie sich jemals Sorgen machen, dass sich die englischen Alphabete irgendwann ändern können und Sie möglicherweise das Geschäft verlieren, können Sie eine harte Codierung vermeiden, sollten jedoch eine etwas schlechtere Leistung erbringen (vergleichbar mit dem Path.GetRandomFileNameAnsatz).
publicstaticstringGetRandomAlphaNumeric(){var chars ='a'.To('z').Concat('0'.To('9')).ToList();returnnewstring(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());}publicstaticIEnumerable<char>To(thischar start,char end){if(end < start)thrownewArgumentOutOfRangeException("the end char should not be less than start char", innerException:null);returnEnumerable.Range(start, end - start +1).Select(i =>(char)i);}
Die letzten beiden Ansätze sehen besser aus, wenn Sie sie beispielsweise zu einer Erweiterungsmethode machen können System.Random.
Die Verwendung chars.Selectist sehr hässlich, da die Ausgabegröße höchstens der Alphabetgröße entspricht.
CodesInChaos
@CodesInChaos Ich bin mir nicht sicher, ob ich dich verstehe. Du meinst im 'a'.To('z')Ansatz?
Nawfal
1
1) chars.Select().Take (n) `funktioniert nur wenn chars.Count >= n. Die Auswahl einer Sequenz, die Sie nicht verwenden, ist etwas uninteressant, insbesondere bei dieser impliziten Längenbeschränkung. Ich würde lieber Enumerable.Rangeoder verwenden Enumerable.Repeat. 2) Die Fehlermeldung "Das Endzeichen sollte kleiner sein als das Startzeichen" ist falsch herum / fehlt a not.
CodesInChaos
@CodesInChaos aber in meinem Fall chars.Countist Weg > n. Auch ich verstehe den unintuitiven Teil nicht. Das macht alle Verwendungen Takeunintuitiv, nicht wahr? Ich glaube es nicht. Vielen Dank für den Tippfehler.
Nawfal
4
Dies wird auf theDailyWTF.com als CodeSOD-Artikel vorgestellt.
22
Nur einige Leistungsvergleiche der verschiedenen Antworten in diesem Thread:
In LinqPad getestet. Für eine Zeichenfolgengröße von 10 wird Folgendes generiert:
von Linq = chdgmevhcy [10]
from Loop = gtnoaryhxr [10]
von Select = rsndbztyby [10]
von GenerateRandomString = owyefjjakj [10]
von SecureFastRandom = VzougLYHYP [10]
von SecureFastRandom-NoCache = oVQXNGmO1S [10]
Und die Leistungszahlen variieren in der Regel geringfügig, gelegentlich NonOptimizedist sie sogar schneller ForLoopund GenerateRandomStringwechseln manchmal , wer an der Spitze steht.
Es wäre interessant zu wissen, welche Dupes erstellt haben.
Rebecca
@Junto - um herauszufinden, was zu Duplikaten führt, so etwas wie var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());, wo Sie durch EachRandomizingMethod... jede Methode ersetzen
Ich dachte daran, konnte aber die nicht alphanumerischen Zeichen nicht loswerden, da das zweite Argument die MINIMUM-Nicht-Alpha-Zeichen sind
ozzy432836
13
Der von Eric J. geschriebene Code ist ziemlich schlampig (es ist ziemlich klar, dass er von vor 6 Jahren stammt ... er würde diesen Code heute wahrscheinlich nicht schreiben), und es gibt sogar einige Probleme.
Im Gegensatz zu einigen der vorgestellten Alternativen ist diese kryptografisch fundiert.
Unwahr ... Es gibt eine Verzerrung im Passwort (wie in einem Kommentar geschrieben), bcdefghdie etwas wahrscheinlicher ist als die anderen (das aliegt nicht daran, GetNonZeroBytesdass keine Bytes mit dem Wert Null generiert werden, also die Verzerrung für diea wird dadurch ausgeglichen), so dass es nicht wirklich kryptografisch klingt.
Dies sollte alle Probleme beheben.
publicstaticstringGetUniqueKey(int size =6,string chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"){
using (var crypto =newRNGCryptoServiceProvider()){var data =newbyte[size];// If chars.Length isn't a power of 2 then there is a bias if// we simply use the modulus operator. The first characters of// chars will be more probable than the last ones.// buffer used if we encounter an unusable random byte. We will// regenerate it in this bufferbyte[] smallBuffer =null;// Maximum random number that can be used without introducing a// biasint maxRandom =byte.MaxValue-((byte.MaxValue+1)% chars.Length);
crypto.GetBytes(data);var result =newchar[size];for(int i =0; i < size; i++){byte v = data[i];while(v > maxRandom){if(smallBuffer ==null){
smallBuffer =newbyte[1];}
crypto.GetBytes(smallBuffer);
v = smallBuffer[0];}
result[i]= chars[v % chars.Length];}returnnewstring(result);}}
Wir verwenden auch benutzerdefinierte zufällige Zeichenfolgen, aber wir haben sie als Helfer für Zeichenfolgen implementiert, damit sie etwas Flexibilität bieten ...
publicstaticstringRandom(thisstring chars,int length =8){var randomString =newStringBuilder();var random =newRandom();for(int i =0; i < length; i++)
randomString.Append(chars[random.Next(chars.Length)]);return randomString.ToString();}
Verwendungszweck
var random ="ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random();
oder
var random ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".Random(16);
Frage: Warum sollte ich meine Zeit damit verschwenden, Enumerable.Rangeanstatt einzutippen "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"?
using System;
using System.Collections.Generic;
using System.Linq;publicclassTest{publicstaticvoidMain(){var randomCharacters =GetRandomCharacters(8,true);Console.WriteLine(newstring(randomCharacters.ToArray()));}privatestaticList<char> getAvailableRandomCharacters(bool includeLowerCase){var integers =Enumerable.Empty<int>();
integers = integers.Concat(Enumerable.Range('A',26));
integers = integers.Concat(Enumerable.Range('0',10));if( includeLowerCase )
integers = integers.Concat(Enumerable.Range('a',26));return integers.Select(i =>(char)i).ToList();}publicstaticIEnumerable<char>GetRandomCharacters(int count,bool includeLowerCase){var characters = getAvailableRandomCharacters(includeLowerCase);var random =newRandom();var result =Enumerable.Range(0, count).Select(_ => characters[random.Next(characters.Count)]);return result;}}
Antwort: Magische Saiten sind SCHLECHT. Hat jemand bemerkt, dass es keine "I " in meiner Zeichenfolge war? Meine Mutter hat mir beigebracht, aus diesem Grund keine magischen Saiten zu benutzen ...
nb 1: Wie viele andere wie @dtb sagten, verwenden Sie es nicht, System.Randomwenn Sie kryptografische Sicherheit benötigen ...
nb 2: Diese Antwort ist nicht die effizienteste oder kürzeste, aber ich wollte, dass der Raum die Antwort von der Frage trennt. Der Zweck meiner Antwort ist eher, vor magischen Fäden zu warnen, als eine ausgefallene innovative Antwort zu liefern.
Alphanumerisch (Groß- / Kleinschreibung ignorieren) ist [A-Z0-9]. Wenn Ihre zufällige Zeichenfolge versehentlich nur [A-HJ-Z0-9]das Ergebnis abdeckt, deckt sie nicht den gesamten zulässigen Bereich ab, was problematisch sein kann.
Wai Ha Lee
Wie wäre das problematisch? Also enthält es nicht I. Liegt es daran, dass es einen Charakter weniger gibt und das das Knacken erleichtert? Was sind die Statistiken zu knackbaren Passwörtern, die 35 Zeichen im Bereich von 36 enthalten? Ich denke, ich würde es lieber riskieren ... oder nur den Zeichenbereich prüfen ... als all diesen zusätzlichen Müll in meinen Code aufzunehmen. Aber das bin ich. Ich meine, um kein Arschloch zu sein, sage ich nur. Manchmal denke ich, dass Programmierer die Tendenz haben, den extrakomplexen Weg zu gehen, um extrakomplex zu sein.
Christine
1
Es vertieft sich auf den Anwendungsfall. Es ist sehr üblich, Zeichen wie Iund Ovon diesen Arten von zufälligen Zeichenfolgen auszuschließen , um zu vermeiden, dass Menschen sie mit 1und verwechseln 0. Wenn Sie sich nicht für eine für Menschen lesbare Zeichenfolge interessieren, ist das in Ordnung, aber wenn jemand etwas eingeben muss, ist es eigentlich klug, diese Zeichen zu entfernen.
Chris Pratt
5
Eine etwas sauberere Version der DTB-Lösung.
var chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";var random =newRandom();varlist=Enumerable.Repeat(0,8).Select(x=>chars[random.Next(chars.Length)]);returnstring.Join("",list);
Nachdem ich die anderen Antworten überprüft und die Kommentare von CodeInChaos sowie die immer noch voreingenommene (wenn auch weniger) Antwort von CodeInChaos berücksichtigt hatte, dachte ich, dass eine endgültige Lösung zum Ausschneiden und Einfügen erforderlich ist. Während ich meine Antwort aktualisierte, beschloss ich, alles zu tun.
In Bezug auf einige andere Antworten - Wenn Sie die Länge der Ausgabe kennen, benötigen Sie keinen StringBuilder. Wenn Sie ToCharArray verwenden, wird das Array erstellt und gefüllt (Sie müssen nicht zuerst ein leeres Array erstellen).
In Bezug auf einige andere Antworten - Sie sollten NextBytes verwenden, anstatt jeweils eine für die Leistung zu erhalten
Technisch gesehen können Sie das Byte-Array für einen schnelleren Zugriff anheften. Es lohnt sich normalerweise, wenn Sie mehr als 6-8 Mal über ein Byte-Array iterieren. (Hier nicht gemacht)
Verwendung von RNGCryptoServiceProvider für beste Zufälligkeit
Gebrauch von Zwischenspeicherung eines 1-MB-Puffers mit zufälligen Daten - Benchmarking zeigt, dass die Zugriffsgeschwindigkeit zwischengespeicherter Einzelbytes ~ 1000x schneller ist - 9 ms über 1 MB gegenüber 989 ms für nicht zwischengespeicherte.
Optimierte Unterdrückung der Vorspannungszone in meiner neuen Klasse.
Endlösung zur Frage:
staticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[Length];SecureFastRandom.GetNextBytesMax(rBytes, biasZone);for(var i =0; i <Length; i++){
rName[i]= charSet[rBytes[i]% charSet.Length];}returnnewstring(rName);}
Aber du brauchst meine neue (ungetestete) Klasse:
/// <summary>/// My benchmarking showed that for RNGCryptoServiceProvider:/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference /// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached/// </summary>classSecureFastRandom{staticbyte[] byteCache =newbyte[1000000];//My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)staticint lastPosition =0;staticint remaining =0;/// <summary>/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function/// </summary>/// <param name="buffer"></param>publicstaticvoidDirectGetBytes(byte[] buffer){
using (var r =newRNGCryptoServiceProvider()){
r.GetBytes(buffer);}}/// <summary>/// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance/// </summary>/// <param name="buffer"></param>publicstaticvoidGetBytes(byte[] buffer){if(buffer.Length> byteCache.Length){DirectGetBytes(buffer);return;}lock(byteCache){if(buffer.Length> remaining){DirectGetBytes(byteCache);
lastPosition =0;
remaining = byteCache.Length;}Buffer.BlockCopy(byteCache, lastPosition, buffer,0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;}}/// <summary>/// Return a single byte from the cache of random data./// </summary>/// <returns></returns>publicstaticbyteGetByte(){lock(byteCache){returnUnsafeGetByte();}}/// <summary>/// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache./// </summary>/// <returns></returns>staticbyteUnsafeGetByte(){if(1> remaining){DirectGetBytes(byteCache);
lastPosition =0;
remaining = byteCache.Length;}
lastPosition++;
remaining--;return byteCache[lastPosition -1];}/// <summary>/// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number./// </summary>/// <param name="buffer"></param>/// <param name="max"></param>publicstaticvoidGetBytesWithMax(byte[] buffer,byte max){if(buffer.Length> byteCache.Length/2)//No point caching for larger sizes{DirectGetBytes(buffer);lock(byteCache){UnsafeCheckBytesMax(buffer, max);}}else{lock(byteCache){if(buffer.Length> remaining)//Recache if not enough remaining, discarding remaining - too much work to join two blocksDirectGetBytes(byteCache);Buffer.BlockCopy(byteCache, lastPosition, buffer,0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;UnsafeCheckBytesMax(buffer, max);}}}/// <summary>/// Checks buffer for bytes equal and above max. Must be called within lock of byteCache./// </summary>/// <param name="buffer"></param>/// <param name="max"></param>staticvoidUnsafeCheckBytesMax(byte[] buffer,byte max){for(int i =0; i < buffer.Length; i++){while(buffer[i]>= max)
buffer[i]=UnsafeGetByte();//Replace all bytes which are equal or above max}}}
Für die Geschichte - meine ältere Lösung für diese Antwort, verwendetes Zufallsobjekt:
privatestaticchar[] charSet ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();static rGen =newRandom();//Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.staticint byteSize =256;//Labelling conveniencestaticint biasZone = byteSize -(byteSize % charSet.Length);staticboolSlightlyMoreSecurityNeeded=true;//Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.publicstringGenerateRandomString(intLength)//Configurable output string length{byte[] rBytes =newbyte[Length];//Do as much before and after lock as possiblechar[] rName =newchar[Length];lock(rGen)//~20-50ns{
rGen.NextBytes(rBytes);for(int i =0; i <Length; i++){while(SlightlyMoreSecurityNeeded&& rBytes[i]>= biasZone)//Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
rBytes[i]= rGen.NextByte();
rName[i]= charSet[rBytes[i]% charSet.Length];}}returnnewstring(rName);}
Performance:
SecureFastRandom - Erster einzelner Lauf = ~ 9-33 ms . Unmerklich. Laufend : 5 ms (manchmal bis zu 13 ms) über 10.000 Iterationen, mit einer einzelnen durchschnittlichen Iteration = 1,5 Mikrosekunden. . Hinweis: Erfordert im Allgemeinen 2, gelegentlich jedoch bis zu 8 Cache-Aktualisierungen - hängt davon ab, wie viele einzelne Bytes die Bias-Zone überschreiten
Zufällig - Erster einzelner Lauf = ~ 0-1 ms . Unmerklich. Laufend : 5 ms über 10.000 Iterationen. Mit einer einzelnen durchschnittlichen Iteration = 0,5 Mikrosekunden. . Etwa die gleiche Geschwindigkeit.
Diese Links sind ein weiterer Ansatz. Diese neue Codebasis könnte um Pufferung erweitert werden. Am wichtigsten war jedoch die Untersuchung verschiedener Ansätze zur Beseitigung von Verzerrungen und das Benchmarking der Geschwindigkeiten und Vor- und Nachteile.
Ich fand einige leichte Leistungsverbesserungen an Ihrer Methode, die das Fasten
drzaus
5
1) Warum all diese magischen Konstanten? Sie spezifiziert die Ausgabelänge drei Mal. Definieren Sie es einfach als Konstante oder Parameter. Sie können charSet.Lengthanstelle von verwenden 62. 2) Eine statische RandomAufladung ohne Sperre bedeutet, dass dieser Code nicht threadsicher ist. 3) Das Reduzieren von 0-255 mod 62 führt eine nachweisbare Vorspannung ein. 4) Sie können nicht ToStringfür ein char-Array verwenden, das immer zurückgibt "System.Char[]". Sie müssen new String(rName)stattdessen verwenden.
CodesInChaos
Danke @CodesInChaos, ich habe damals noch nie an diese Dinge gedacht. Immer noch nur Random-Klasse, aber das sollte besser sein. Ich könnte mir keinen besseren Weg vorstellen, um Bias-Eingänge zu erkennen und zu korrigieren.
Todd
Es ist ein bisschen albern, mit einem schwachen RNG ( System.Random) zu beginnen und dann sorgfältig jegliche Verzerrung in Ihrem eigenen Code zu vermeiden. Der Ausdruck "Polieren eines Trottels" kommt mir in den Sinn.
CodesInChaos
@CodesInChaos Und jetzt hat der Lehrling seinen Meister übertroffen
Todd
4
Schrecklich, ich weiß, aber ich konnte mir einfach nicht helfen:
namespace ConsoleApplication2{
using System;
using System.Text.RegularExpressions;classProgram{staticvoidMain(string[] args){Random adomRng =newRandom();string rndString =string.Empty;char c;for(int i =0; i <8; i++){while(!Regex.IsMatch((c=Convert.ToChar(adomRng.Next(48,128))).ToString(),"[A-Za-z0-9]"));
rndString += c;}Console.WriteLine(rndString +Environment.NewLine);}}}
Ich habe nach einer genaueren Antwort gesucht, bei der ich das Format der zufälligen Zeichenfolge steuern möchte, und bin auf diesen Beitrag gestoßen. Zum Beispiel: Nummernschilder (von Autos) haben ein bestimmtes Format (pro Land) und ich wollte zufällige Nummernschilder erstellen.
Ich habe mich dazu entschlossen, meine eigene Erweiterungsmethode von Random zu schreiben. (Dies dient dazu, dasselbe zufällige Objekt wiederzuverwenden, da Sie in Multithreading-Szenarien Doppelte haben könnten.) Ich habe eine Liste erstellt ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), werde aber auch die Erweiterungsklasse hier kopieren:
voidMain(){Random rnd =newRandom();
rnd.GetString("1-###-000").Dump();}publicstaticclassRandomExtensions{publicstaticstringGetString(thisRandom random,string format){// Based on http://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c// Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)StringBuilder result =newStringBuilder();for(int formatIndex =0; formatIndex < format.Length; formatIndex++){switch(format.ToUpper()[formatIndex]){case'0': result.Append(getRandomNumeric(random));break;case'#': result.Append(getRandomCharacter(random));break;default: result.Append(format[formatIndex]);break;}}return result.ToString();}privatestaticchar getRandomCharacter(Random random){string chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";return chars[random.Next(chars.Length)];}privatestaticchar getRandomNumeric(Random random){string nums ="0123456789";return nums[random.Next(nums.Length)];}}
Die Verwendung einer Eigenschaft für etwas, das sich bei jedem Zugriff ändert, ist eher zweifelhaft. Ich würde empfehlen, stattdessen eine Methode zu verwenden.
CodesInChaos
2
RNGCryptoServiceProvidersollte nach Gebrauch entsorgt werden.
Tsahi Asher
Ich habe das IDisposable-Problem behoben, aber dies ist immer noch sehr zweifelhaft, da für jeden Buchstaben ein neuer RNGCryptoServiceProvider erstellt wurde.
Piojo
@CodesInChaos fertig, jetzt eine Methode.
Matas Vaitkevicius
3
Versuchen Sie, zwei Teile zu kombinieren: eindeutig (Sequenz, Zähler oder Datum) und zufällig
publicclassRandomStringGenerator{publicstaticstringGen(){returnConvertToBase(DateTime.UtcNow.ToFileTimeUtc())+GenRandomStrings(5);//keep length fixed at least of one part}privatestaticstringGenRandomStrings(int strLen){var result =string.Empty;varGen=newRNGCryptoServiceProvider();var data =newbyte[1];while(result.Length< strLen){Gen.GetNonZeroBytes(data);int code = data[0];if(code >48&& code <57||// 0-9
code >65&& code <90||// A-Z
code >97&& code <122// a-z){
result +=Convert.ToChar(code);}}return result;}privatestaticstringConvertToBase(long num,int nbase =36){var chars ="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//if you wish make algorithm more secure - change order of letter here// check if we can convert to another baseif(nbase <2|| nbase > chars.Length)returnnull;int r;var newNumber =string.Empty;// in r we have the offset of the char that was converted to the new basewhile(num >= nbase){
r =(int)(num % nbase);
newNumber = chars[r]+ newNumber;
num = num / nbase;}// the last number to convert
newNumber = chars[(int)num]+ newNumber;return newNumber;}}
1) Sie können Zeichenliterale anstelle der diesen Zeichen zugeordneten ASCII-Werte verwenden. 2) Sie haben einen Fehler in Ihrem Intervall-Matching-Code. Sie müssen <=und >=anstelle von <und verwenden >. 3) Ich würde die unnötigen Klammern um die &&Ausdrücke hinzufügen, um zu verdeutlichen, dass sie Vorrang haben, aber das ist natürlich nur eine stilistische Wahl.
CodesInChaos
+ 1 Gut zum Entfernen von Verzerrungen und zum Hinzufügen von Tests. Ich bin mir nicht sicher, warum Sie Ihrer zufälligen Zeichenfolge eine vom Zeitstempel abgeleitete Zeichenfolge voranstellen. Außerdem müssen Sie Ihren RNGCryptoServiceProvider
Montag,
2
Eine Lösung ohne Random:
var chars =Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",8);var randomStr =newstring(chars.SelectMany(str => str).OrderBy(c =>Guid.NewGuid()).Take(8).ToArray());
NewGuid verwendet intern zufällig. Das wird also immer noch zufällig verwendet, es versteckt es nur.
Wedge
2
Hier ist eine Variante von Eric Js Lösung für WinRT (Windows Store App), dh kryptografisch einwandfrei:
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newStringBuilder(length);for(int i =0; i < length;++i){
result.Append(CryptographicBuffer.GenerateRandomNumber()% chars.Length);}return result.ToString();}
Wenn Leistung wichtig ist (insbesondere wenn die Länge hoch ist):
publicstaticstringGenerateRandomString(int length){var chars ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";var result =newSystem.Text.StringBuilder(length);var bytes =CryptographicBuffer.GenerateRandom((uint)length *4).ToArray();for(int i =0; i < bytes.Length; i +=4){
result.Append(BitConverter.ToUInt32(bytes, i)% chars.Length);}return result.ToString();}
Dies ist nicht kryptografisch fundiert. Es gibt eine kleine Vorspannung aufgrund des Modulbetriebs, der nicht die gesamte Breite von ulong gleichmäßig auf 62 Zeichen verteilt.
Lie Ryan
1
Ich weiß, dass dies nicht der beste Weg ist. Aber du kannst es versuchen.
string str =Path.GetRandomFileName();//This method returns a random file name of 11 characters
str = str.Replace(".","");Console.WriteLine("Random string: "+ str);
Wie ist diese eine Zeile? Console.WriteLine ($ "Zufällige Zeichenfolge: {Path.GetRandomFileName (). Replace (". "," ")}"); ist eine Zeile.
PmanAce
1
Ich weiß nicht, wie kryptografisch das klingt, aber es ist bei weitem lesbarer und prägnanter als die komplizierteren Lösungen (imo), und es sollte "zufälliger" sein als System.Randombasierende Lösungen.
Zugegeben, es ist nicht auf Geschwindigkeit optimiert. Wenn es also wichtig ist, jede Sekunde Millionen zufälliger Zeichenfolgen zu generieren, versuchen Sie es mit einer anderen!
HINWEIS: Diese Lösung erlaubt keine Wiederholungen von Symbolen im Alphabet. Das Alphabet MUSS gleich oder größer als die Ausgabezeichenfolge sein. Daher ist dieser Ansatz unter bestimmten Umständen weniger wünschenswert. Dies hängt alles von Ihrem Anwendungsfall ab.
Wenn Ihre Werte nicht völlig zufällig sind, sondern tatsächlich von etwas abhängen, können Sie einen md5- oder sha1-Hash dieses „Etwas“ berechnen und ihn dann auf die gewünschte Länge abschneiden.
Sie können auch eine Guid generieren und abschneiden.
1) statische Methoden sollten threadsicher sein. 2) Was bringt es, den Index zu erhöhen, anstatt das Ergebnis von random.Nextdirekt zu verwenden? Kompliziert den Code und erreicht nichts Nützliches.
CodesInChaos
0
Hier ist ein Mechanismus zum Generieren einer zufälligen alphanumerischen Zeichenfolge (ich verwende diese, um Passwörter und Testdaten zu generieren), ohne das Alphabet und die Zahlen zu definieren.
CleanupBase64 entfernt die erforderlichen Teile in der Zeichenfolge und fügt weiterhin rekursiv zufällige alphanumerische Buchstaben hinzu.
publicstaticstringGenerateRandomString(int length){var numArray =newbyte[length];newRNGCryptoServiceProvider().GetBytes(numArray);returnCleanUpBase64String(Convert.ToBase64String(numArray), length);}privatestaticstringCleanUpBase64String(string input,int maxLength){
input = input.Replace("-","");
input = input.Replace("=","");
input = input.Replace("/","");
input = input.Replace("+","");
input = input.Replace(" ","");while(input.Length< maxLength)
input = input +GenerateRandomString(maxLength);return input.Length<= maxLength ?
input.ToUpper()://In my case I want capital letters
input.ToUpper().Substring(0, maxLength);}
Sie haben erklärt GenerateRandomStringund rufen GetRandomStringvon innen an SanitiseBase64String. Auch haben Sie erklärt SanitiseBase64String und Call - CleanUpBase64Stringin GenerateRandomString.
Wai Ha Lee
0
Es gibt eines der großartigen Nuget-Pakete , die dies so einfach machen.
var myObject =newFaker<MyObject>().RuleFor(p => p.MyAlphaNumericProperty, f => f.Random.AlphaNumeric(/*lenght*/7)).Generate();
Nicht 100% sicher, da ich hier nicht JEDE Option getestet habe, aber von denen, die ich getestet habe, ist diese die schnellste. Es wurde mit einer Stoppuhr gemessen und es wurden 9 bis 10 Ticks angezeigt. Wenn also Geschwindigkeit wichtiger ist als Sicherheit, versuchen Sie Folgendes:
privatestaticRandom random =newRandom();publicstaticstringRandom(int length){var stringChars =newchar[length];for(int i =0; i < length; i++){
stringChars[i]=(char)random.Next(0x30,0x7a);returnnewstring(stringChars);}}
Random
Klasse basierende Methode verwenden sollten , um Kennwörter zu generieren. Die AussaatRandom
hat eine sehr geringe Entropie, daher ist sie nicht wirklich sicher. Verwenden Sie ein kryptografisches PRNG für Kennwörter.Antworten:
Ich habe gehört, dass LINQ das neue Schwarz ist. Hier ist mein Versuch, LINQ zu verwenden:
(Hinweis: Die Verwendung der
Random
Klasse macht dies für sicherheitsrelevante Zwecke wie das Erstellen von Kennwörtern oder Token ungeeignet . Verwenden Sie dieRNGCryptoServiceProvider
Klasse, wenn Sie einen starken Zufallszahlengenerator benötigen.)quelle
return new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Nicht so elegant wie die Linq-Lösung.
(Hinweis: Die Verwendung der
Random
Klasse macht dies für sicherheitsrelevante Zwecke wie das Erstellen von Kennwörtern oder Token ungeeignet . Verwenden Sie dieRNGCryptoServiceProvider
Klasse, wenn Sie einen starken Zufallszahlengenerator benötigen.)quelle
GetRandomFileName
Lösung von Adam Porad ist schneller, erlaubt jedoch keine Kontrolle über die verwendeten Zeichen und die maximal mögliche Länge beträgt 11 Zeichen. Douglas 'Guid
Lösung ist blitzschnell, aber die Zeichen sind auf A-F0-9 beschränkt und die maximal mögliche Länge beträgt 32 Zeichen.GetRandomFileName
aber dann (a) würden Sie Ihren Leistungsvorteil verlieren und (b) Ihr Code würde komplizierter werden.System.Random
ist nicht für die Sicherheit geeignet.Im Gegensatz zu einigen der vorgestellten Alternativen ist diese kryptografisch fundiert .
Basierend auf einer Diskussion der Alternativen hier und aktualisiert / modifiziert basierend auf den Kommentaren unten.
Hier ist ein kleines Testkabel, das die Verteilung der Zeichen in der alten und aktualisierten Ausgabe demonstriert. Eine ausführliche Beschreibung der Analyse der Zufälligkeit finden Sie unter random.org.
quelle
RNGCSP
?) Die Verwendung von Mod zum Indizieren in daschars
Array bedeutet, dass Sie eine voreingenommene Ausgabe erhalten, es sei denn,chars.Length
es handelt sich um einen Divisor von 256.4*maxSize
zufällige Bytes anzufordern und dann zu verwenden(UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length
. Ich würde auchGetBytes
anstelle von verwendenGetNonZeroBytes
. Und schließlich können Sie den ersten Anruf an entfernenGetNonZeroBytes
. Sie verwenden das Ergebnis nicht.Lösung 1 - größter Bereich mit der flexibelsten Länge
Diese Lösung hat mehr Reichweite als die Verwendung einer GUID, da eine GUID einige feste Bits hat, die immer gleich und daher nicht zufällig sind. Beispielsweise ist das hexadezimale 13-Zeichen immer "4" - zumindest in einer GUID der Version 6.
Mit dieser Lösung können Sie auch eine Zeichenfolge beliebiger Länge generieren.
Lösung 2 - Eine Codezeile - gut für bis zu 22 Zeichen
Sie können keine Zeichenfolgen generieren, solange Lösung 1 vorhanden ist und die Zeichenfolge aufgrund fester Bits in den GUIDs nicht denselben Bereich haben. In vielen Fällen reicht dies jedoch aus.
Lösung 3 - Etwas weniger Code
Meistens hier für historische Zwecke. Es wird etwas weniger Code verwendet, was jedoch die Kosten für eine geringere Reichweite mit sich bringt. Da Hex anstelle von base64 verwendet wird, sind im Vergleich zu den anderen Lösungen mehr Zeichen erforderlich, um denselben Bereich darzustellen.
Dies bedeutet eine höhere Kollisionswahrscheinlichkeit. Durch Testen mit 100.000 Iterationen von 8 Zeichenfolgen wurde ein Duplikat generiert.
quelle
Hier ist ein Beispiel, das ich aus dem Beispiel von Sam Allen bei gestohlen habe Dot Net Perls
Wenn Sie nur 8 Zeichen benötigen, verwenden Sie Path.GetRandomFileName () im System.IO-Namespace. Sam sagt, dass die Verwendung der "Path.GetRandomFileName-Methode hier manchmal überlegen ist, da sie RNGCryptoServiceProvider für eine bessere Zufälligkeit verwendet. Sie ist jedoch auf 11 zufällige Zeichen beschränkt."
GetRandomFileName gibt immer eine 12-stellige Zeichenfolge mit einem Punkt am 9. Zeichen zurück. Sie müssen also den Punkt entfernen (da dies nicht zufällig ist) und dann 8 Zeichen aus der Zeichenfolge entfernen. Eigentlich könnte man einfach die ersten 8 Zeichen nehmen und sich keine Sorgen um den Zeitraum machen.
PS: Danke Sam
quelle
Die Hauptziele meines Codes sind:
Die erste Eigenschaft wird erreicht, indem ein 64-Bit-Wert modulo der Alphabetgröße verwendet wird. Bei kleinen Alphabeten (wie den 62 Zeichen aus der Frage) führt dies zu einer vernachlässigbaren Verzerrung. Die zweite und dritte Eigenschaft werden durch Verwendung von
RNGCryptoServiceProvider
anstelle von erreichtSystem.Random
.quelle
Das einfachste:
Sie können eine bessere Leistung erzielen, wenn Sie das char-Array hart codieren und sich auf Folgendes verlassen
System.Random
:Wenn Sie sich jemals Sorgen machen, dass sich die englischen Alphabete irgendwann ändern können und Sie möglicherweise das Geschäft verlieren, können Sie eine harte Codierung vermeiden, sollten jedoch eine etwas schlechtere Leistung erbringen (vergleichbar mit dem
Path.GetRandomFileName
Ansatz).Die letzten beiden Ansätze sehen besser aus, wenn Sie sie beispielsweise zu einer Erweiterungsmethode machen können
System.Random
.quelle
chars.Select
ist sehr hässlich, da die Ausgabegröße höchstens der Alphabetgröße entspricht.'a'.To('z')
Ansatz?chars.Select()
.Take (n) `funktioniert nur wennchars.Count >= n
. Die Auswahl einer Sequenz, die Sie nicht verwenden, ist etwas uninteressant, insbesondere bei dieser impliziten Längenbeschränkung. Ich würde lieberEnumerable.Range
oder verwendenEnumerable.Repeat
. 2) Die Fehlermeldung "Das Endzeichen sollte kleiner sein als das Startzeichen" ist falsch herum / fehlt anot
.chars.Count
ist Weg> n
. Auch ich verstehe den unintuitiven Teil nicht. Das macht alle VerwendungenTake
unintuitiv, nicht wahr? Ich glaube es nicht. Vielen Dank für den Tippfehler.Nur einige Leistungsvergleiche der verschiedenen Antworten in diesem Thread:
Methoden & Setup
Ergebnisse
In LinqPad getestet. Für eine Zeichenfolgengröße von 10 wird Folgendes generiert:
Und die Leistungszahlen variieren in der Regel geringfügig, gelegentlich
NonOptimized
ist sie sogar schnellerForLoop
undGenerateRandomString
wechseln manchmal , wer an der Spitze steht.quelle
var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());
, wo Sie durchEachRandomizingMethod
... jede Methode ersetzenEine Codezeile
Membership.GeneratePassword()
macht den Trick :)Hier ist eine Demo dafür.
quelle
Der von Eric J. geschriebene Code ist ziemlich schlampig (es ist ziemlich klar, dass er von vor 6 Jahren stammt ... er würde diesen Code heute wahrscheinlich nicht schreiben), und es gibt sogar einige Probleme.
Unwahr ... Es gibt eine Verzerrung im Passwort (wie in einem Kommentar geschrieben),
bcdefgh
die etwas wahrscheinlicher ist als die anderen (dasa
liegt nicht daran,GetNonZeroBytes
dass keine Bytes mit dem Wert Null generiert werden, also die Verzerrung für diea
wird dadurch ausgeglichen), so dass es nicht wirklich kryptografisch klingt.Dies sollte alle Probleme beheben.
quelle
Wir verwenden auch benutzerdefinierte zufällige Zeichenfolgen, aber wir haben sie als Helfer für Zeichenfolgen implementiert, damit sie etwas Flexibilität bieten ...
Verwendungszweck
oder
quelle
Mein einfacher einzeiliger Code funktioniert für mich :)
Um dies für eine beliebige Zeichenfolge zu erweitern
quelle
Eine andere Möglichkeit könnte darin bestehen, Linq zu verwenden und zufällige Zeichen zu einem Stringbuilder zusammenzufassen.
quelle
Frage: Warum sollte ich meine Zeit damit verschwenden,
Enumerable.Range
anstatt einzutippen"ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"
?Antwort: Magische Saiten sind SCHLECHT. Hat jemand bemerkt, dass es keine "
I
" in meiner Zeichenfolge war? Meine Mutter hat mir beigebracht, aus diesem Grund keine magischen Saiten zu benutzen ...nb 1: Wie viele andere wie @dtb sagten, verwenden Sie es nicht,
System.Random
wenn Sie kryptografische Sicherheit benötigen ...nb 2: Diese Antwort ist nicht die effizienteste oder kürzeste, aber ich wollte, dass der Raum die Antwort von der Frage trennt. Der Zweck meiner Antwort ist eher, vor magischen Fäden zu warnen, als eine ausgefallene innovative Antwort zu liefern.
quelle
I
?"[A-Z0-9]
. Wenn Ihre zufällige Zeichenfolge versehentlich nur[A-HJ-Z0-9]
das Ergebnis abdeckt, deckt sie nicht den gesamten zulässigen Bereich ab, was problematisch sein kann.I
. Liegt es daran, dass es einen Charakter weniger gibt und das das Knacken erleichtert? Was sind die Statistiken zu knackbaren Passwörtern, die 35 Zeichen im Bereich von 36 enthalten? Ich denke, ich würde es lieber riskieren ... oder nur den Zeichenbereich prüfen ... als all diesen zusätzlichen Müll in meinen Code aufzunehmen. Aber das bin ich. Ich meine, um kein Arschloch zu sein, sage ich nur. Manchmal denke ich, dass Programmierer die Tendenz haben, den extrakomplexen Weg zu gehen, um extrakomplex zu sein.I
undO
von diesen Arten von zufälligen Zeichenfolgen auszuschließen , um zu vermeiden, dass Menschen sie mit1
und verwechseln0
. Wenn Sie sich nicht für eine für Menschen lesbare Zeichenfolge interessieren, ist das in Ordnung, aber wenn jemand etwas eingeben muss, ist es eigentlich klug, diese Zeichen zu entfernen.Eine etwas sauberere Version der DTB-Lösung.
Ihre Stilvorlieben können variieren.
quelle
quelle
Nachdem ich die anderen Antworten überprüft und die Kommentare von CodeInChaos sowie die immer noch voreingenommene (wenn auch weniger) Antwort von CodeInChaos berücksichtigt hatte, dachte ich, dass eine endgültige Lösung zum Ausschneiden und Einfügen erforderlich ist. Während ich meine Antwort aktualisierte, beschloss ich, alles zu tun.
Eine aktuelle Version dieses Codes finden Sie im neuen Hg-Repository auf Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Ich empfehle Ihnen, den Code zu kopieren und einzufügen von: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs-vdef (stellen Sie sicher , klicken Klicken Sie auf die Schaltfläche "Roh", um das Kopieren zu vereinfachen und sicherzustellen, dass Sie über die neueste Version verfügen. Ich denke, dieser Link führt zu einer bestimmten Version des Codes, nicht zu der neuesten.
Aktualisierte Notizen:
Endlösung zur Frage:
Aber du brauchst meine neue (ungetestete) Klasse:
Für die Geschichte - meine ältere Lösung für diese Antwort, verwendetes Zufallsobjekt:
Performance:
Schauen Sie sich auch an:
Diese Links sind ein weiterer Ansatz. Diese neue Codebasis könnte um Pufferung erweitert werden. Am wichtigsten war jedoch die Untersuchung verschiedener Ansätze zur Beseitigung von Verzerrungen und das Benchmarking der Geschwindigkeiten und Vor- und Nachteile.
quelle
charSet.Length
anstelle von verwenden62
. 2) Eine statischeRandom
Aufladung ohne Sperre bedeutet, dass dieser Code nicht threadsicher ist. 3) Das Reduzieren von 0-255 mod 62 führt eine nachweisbare Vorspannung ein. 4) Sie können nichtToString
für ein char-Array verwenden, das immer zurückgibt"System.Char[]"
. Sie müssennew String(rName)
stattdessen verwenden.System.Random
) zu beginnen und dann sorgfältig jegliche Verzerrung in Ihrem eigenen Code zu vermeiden. Der Ausdruck "Polieren eines Trottels" kommt mir in den Sinn.Schrecklich, ich weiß, aber ich konnte mir einfach nicht helfen:
quelle
Ich habe nach einer genaueren Antwort gesucht, bei der ich das Format der zufälligen Zeichenfolge steuern möchte, und bin auf diesen Beitrag gestoßen. Zum Beispiel: Nummernschilder (von Autos) haben ein bestimmtes Format (pro Land) und ich wollte zufällige Nummernschilder erstellen.
Ich habe mich dazu entschlossen, meine eigene Erweiterungsmethode von Random zu schreiben. (Dies dient dazu, dasselbe zufällige Objekt wiederzuverwenden, da Sie in Multithreading-Szenarien Doppelte haben könnten.) Ich habe eine Liste erstellt ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), werde aber auch die Erweiterungsklasse hier kopieren:
quelle
Jetzt im Einzeiler-Geschmack.
quelle
RNGCryptoServiceProvider
sollte nach Gebrauch entsorgt werden.Versuchen Sie, zwei Teile zu kombinieren: eindeutig (Sequenz, Zähler oder Datum) und zufällig
Tests:
quelle
<=
und>=
anstelle von<
und verwenden>
. 3) Ich würde die unnötigen Klammern um die&&
Ausdrücke hinzufügen, um zu verdeutlichen, dass sie Vorrang haben, aber das ist natürlich nur eine stilistische Wahl.Eine Lösung ohne
Random
:quelle
Hier ist eine Variante von Eric Js Lösung für WinRT (Windows Store App), dh kryptografisch einwandfrei:
Wenn Leistung wichtig ist (insbesondere wenn die Länge hoch ist):
quelle
Ich weiß, dass dies nicht der beste Weg ist. Aber du kannst es versuchen.
quelle
Ich weiß nicht, wie kryptografisch das klingt, aber es ist bei weitem lesbarer und prägnanter als die komplizierteren Lösungen (imo), und es sollte "zufälliger" sein als
System.Random
basierende Lösungen.Ich kann mich nicht entscheiden, ob ich diese oder die nächste Version für "hübscher" halte, aber sie liefern genau die gleichen Ergebnisse:
Zugegeben, es ist nicht auf Geschwindigkeit optimiert. Wenn es also wichtig ist, jede Sekunde Millionen zufälliger Zeichenfolgen zu generieren, versuchen Sie es mit einer anderen!
HINWEIS: Diese Lösung erlaubt keine Wiederholungen von Symbolen im Alphabet. Das Alphabet MUSS gleich oder größer als die Ausgabezeichenfolge sein. Daher ist dieser Ansatz unter bestimmten Umständen weniger wünschenswert. Dies hängt alles von Ihrem Anwendungsfall ab.
quelle
Wenn Ihre Werte nicht völlig zufällig sind, sondern tatsächlich von etwas abhängen, können Sie einen md5- oder sha1-Hash dieses „Etwas“ berechnen und ihn dann auf die gewünschte Länge abschneiden.
Sie können auch eine Guid generieren und abschneiden.
quelle
quelle
random.Next
direkt zu verwenden? Kompliziert den Code und erreicht nichts Nützliches.Hier ist ein Mechanismus zum Generieren einer zufälligen alphanumerischen Zeichenfolge (ich verwende diese, um Passwörter und Testdaten zu generieren), ohne das Alphabet und die Zahlen zu definieren.
CleanupBase64 entfernt die erforderlichen Teile in der Zeichenfolge und fügt weiterhin rekursiv zufällige alphanumerische Buchstaben hinzu.
quelle
GenerateRandomString
und rufenGetRandomString
von innen anSanitiseBase64String
. Auch haben Sie erklärtSanitiseBase64String
und Call -CleanUpBase64String
inGenerateRandomString
.Es gibt eines der großartigen Nuget-Pakete , die dies so einfach machen.
Eines der guten Beispiele ist hier .
quelle
Nicht 100% sicher, da ich hier nicht JEDE Option getestet habe, aber von denen, die ich getestet habe, ist diese die schnellste. Es wurde mit einer Stoppuhr gemessen und es wurden 9 bis 10 Ticks angezeigt. Wenn also Geschwindigkeit wichtiger ist als Sicherheit, versuchen Sie Folgendes:
quelle