Generierung eines zufälligen Strings in Go: Vollständiger Leitfaden mit Code

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Wie generiert man einen zufälligen String in Go, ohne verrückt zu werden?

\n\n

Haben Sie jemals eine Situation erlebt, in der Sie schnell eine eindeutige ID, ein temporäres Passwort oder einen Token für eine API erstellen mussten? Wenn Sie in Go programmieren, werden Sie früher oder später vor der Frage stehen: „Wie generiere ich einen zufälligen String fester Länge?“. Diese Frage hat auf Stack Overflow tausende Aufrufe erhalten, und das zu Recht – die scheinbar einfache Aufgabe birgt einige Fallstricke.

\n\n

In diesem Artikel behandeln wir die Generierung eines zufälligen Strings in Go von einfachen Lösungen bis hin zu Production-Ready-Ansätzen. Sie erfahren, warum math/rand gefährlich sein kann, wie Sie crypto/rand für die Sicherheit verwenden und wie Sie eleganten Code ohne unnötige Abhängigkeiten schreiben.

\n\n

Warum sollte man math/rand nicht für Passwörter verwenden?

\n\n

Beginnen wir mit der beliebtesten, aber nicht immer richtigen Lösung. Viele Anfänger schreiben so etwas wie:

\n\n
package main\n\nimport (\n    "math/rand"\n    "time"\n)\n\nconst letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"\n\nfunc RandString(n int) string {\n    b := make([]byte, n)\n    for i := range b {\n        b[i] = letters[rand.Intn(len(letters))]\n    }\n    return string(b)\n}\n\nfunc main() {\n    rand.Seed(time.Now().UnixNano())\n    println(RandString(10))\n}
\n\n

Dieser Code funktioniert, hat aber einen schwerwiegenden Nachteil: math/rand verwendet einen deterministischen Algorithmus. Wenn ein Angreifer den Seed (oder die Generierungszeit) kennt, kann er die gesamte Sequenz reproduzieren. Für Testdaten oder Dateinamen ist das in Ordnung, aber für geheime Token und Passwörter ist es absolut nicht geeignet.

\n\n

Verwendung von crypto/rand: Sichere Generierung eines zufälligen Strings in Go

\n\n

Für eine Production-Umgebung ist die richtige Wahl das Paket crypto/rand. Es verwendet einen kryptografisch sicheren Zufallszahlengenerator des Betriebssystems. So sieht die Generierung eines zufälligen Strings in Go mit crypto/rand aus:

\n\n
package main\n\nimport (\n    "crypto/rand"\n    "math/big"\n)\n\nconst charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()"\n\nfunc SecureRandomString(length int) (string, error) {\n    result := make([]byte, length)\n    for i := range result {\n        num, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))\n        if err != nil {\n            return "", err\n        }\n        result[i] = charset[num.Int64()]\n    }\n    return string(result), nil\n}\n\nfunc main() {\n    str, err := SecureRandomString(16)\n    if err != nil {\n        panic(err)\n    }\n    println(str)\n}
\n\n

Beachten Sie: Wir verwenden rand.Int mit rand.Reader – dies garantiert, dass jedes Zeichen zufällig und unvorhersehbar ausgewählt wird. Für einen zufälligen String in Go ist dies der Goldstandard.

\n\n

Leistungsoptimierung: Wie man die Generierung beschleunigt

\n\n

Eine Schleife mit einem Aufruf von rand.Int für jedes Zeichen kann bei der Generierung von Hunderttausenden von Strings langsam sein. Die Lösung besteht darin, alle zufälligen Bytes auf einmal zu generieren und sie dann auf unser Alphabet abzubilden. Dieser Trick wird auf Stack Overflow oft im Zusammenhang mit Golang random string diskutiert:

\n\n
package main\n\nimport (\n    "crypto/rand"\n    "encoding/binary"\n)\n\nconst charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"\n\nfunc FastRandomString(length int) string {\n    result := make([]byte, length)\n    // Generieren Sie zufällige 64-Bit-Zahlen\n    buf := make([]byte, 8*length)\n    if _, err := rand.Read(buf); err != nil {\n        panic(err)\n    }\n    for i := 0; i < length; i++ {\n        // Nehmen Sie 8 Bytes für jedes Zeichen\n        val := binary.LittleEndian.Uint64(buf[i*8 : (i+1)*8])\n        // Vermeiden Sie Verzerrung (Bias) mit Modulo\n        result[i] = charset[val%uint64(len(charset))]\n    }\n    return string(result)\n}\n\nfu                

Blogs

Buchempfehlungen