Generación de cadenas aleatorias en Go: guía completa con código

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Cómo generar una cadena aleatoria en Go sin volverse loco?

\n\n

¿Alguna vez te has encontrado en una situación donde necesitas crear rápidamente un identificador único, una contraseña temporal o un token para una API? Si programas en Go, tarde o temprano te enfrentarás a la pregunta: «¿Cómo generar una cadena aleatoria de longitud fija?». Esta pregunta ha acumulado miles de visitas en Stack Overflow, y con razón — una tarea que parece simple esconde varios escollos.

\n\n

En este artículo, analizaremos la generación de cadenas aleatorias en Go desde soluciones simples hasta enfoques listos para producción. Aprenderás por qué math/rand puede ser peligroso, cómo usar crypto/rand para seguridad y cómo escribir código elegante sin dependencias innecesarias.

\n\n

¿Por qué no deberías usar math/rand para contraseñas?

\n\n

Empecemos con la solución más popular, pero no siempre correcta. Muchos principiantes escriben algo como:

\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

Este código funciona, pero tiene un grave defecto: math/rand utiliza un algoritmo determinista. Si un atacante descubre la semilla (o la hora de generación), podrá reproducir toda la secuencia. Para datos de prueba o nombres de archivos está bien, pero para tokens secretos y contraseñas — categóricamente no.

\n\n

Uso de crypto/rand: generación segura de cadenas aleatorias en Go

\n\n

Para entornos de producción, la elección correcta es el paquete crypto/rand. Utiliza un generador de números aleatorios criptográficamente seguro del sistema operativo. Así es como se ve la generación de cadenas aleatorias en Go con 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

Observa: usamos rand.Int con rand.Reader — esto garantiza que cada carácter se selecciona de forma aleatoria e impredecible. Para cadenas aleatorias en Go, este es el estándar de oro.

\n\n

Optimización del rendimiento: cómo acelerar la generación

\n\n

El bucle que llama a rand.Int para cada carácter puede ser lento al generar cientos de miles de cadenas. La solución es generar todos los bytes aleatorios de una sola vez y luego mapearlos a nuestro alfabeto. Este truco se discute a menudo en Stack Overflow en el contexto 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    // Generamos números aleatorios 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        // Tomamos 8 bytes para cada carácter\n        val := binary.LittleEndian.Uint64(buf[i*8 : (i+1)*8])\n        // Evitamos el sesgo (bias) usando el módulo\n        result[i] = charset[val%uint64(len(charset))]\n    }\n    return string(result)\n}\n\nfu                

Blogs

Book Recommendations