Génération de chaîne aléatoire en Go : guide complet avec code

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Comment générer une chaîne aléatoire en Go sans perdre la tête ?

\n\n

Avez-vous déjà été confronté à une situation où vous deviez rapidement créer un identifiant unique, un mot de passe temporaire ou un jeton pour une API ? Si vous programmez en Go, tôt ou tard vous vous poserez la question : « Comment générer une chaîne aléatoire de longueur fixe ? ». Cette question a recueilli des milliers de vues sur Stack Overflow, et ce n'est pas pour rien — une tâche apparemment simple cache plusieurs pièges.

\n\n

Dans cet article, nous allons détailler la génération de chaîne aléatoire en Go des solutions simples aux approches prêtes pour la production. Vous découvrirez pourquoi math/rand peut être dangereux, comment utiliser crypto/rand pour la sécurité et comment écrire un code élégant sans dépendances superflues.

\n\n

Pourquoi ne pas utiliser math/rand pour les mots de passe ?

\n\n

Commençons par la solution la plus populaire, mais pas toujours correcte. De nombreux débutants écrivent quelque chose comme :

\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

Ce code fonctionne, mais il présente un défaut majeur : math/rand utilise un algorithme déterministe. Si un attaquant découvre la seed (ou l'heure de génération), il pourra reproduire toute la séquence. Pour des données de test ou des noms de fichiers, c'est acceptable, mais pour des jetons secrets et mots de passe — absolument pas.

\n\n

Utilisation de crypto/rand : génération sécurisée de chaîne aléatoire en Go

\n\n

Pour un environnement de production, le bon choix est le paquet crypto/rand. Il utilise un générateur de nombres aléatoires cryptographiquement sûr du système d'exploitation. Voici à quoi ressemble la génération de chaîne aléatoire en Go avec crypto/rand :

\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

Notez que nous utilisons rand.Int avec rand.Reader — cela garantit que chaque caractère est choisi de manière aléatoire et imprévisible. Pour une chaîne aléatoire en Go, c'est l'étalon-or.

\n\n

Optimisation des performances : comment accélérer la génération

\n\n

La boucle avec l'appel à rand.Int pour chaque caractère peut être lente lors de la génération de centaines de milliers de chaînes. La solution consiste à générer tous les octets aléatoires en une seule fois, puis à les mapper sur notre alphabet. Cette astuce est souvent discutée sur Stack Overflow dans le contexte de Golang random string :

\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    // Générons des nombres aléatoires de 64 bits\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        // Prenons 8 octets pour chaque caractère\n        val := binary.LittleEndian.Uint64(buf[i*8 : (i+1)*8])\n        // Évitons le biais (bias) avec le modulo\n        result[i] = charset[val%uint64(len(charset))]\n    }\n    return string(result)\n}\n\nfu                

Blogs

Book Recommendations