Pregunta 1¿A qué módulo deberías recurrir para generar un token de restablecimiento de contraseña?
random y secrets — Eligiendo el tipo correcto de números aleatorios
Este artículo forma parte del Curso de Python, con el que dominarás desde cero las habilidades necesarias para usar Python, desde lo básico hasta lo avanzado.
Pseudoaleatorios reproducibles con random.randint / choice / shuffle / sample y seed, frente a los tokens impredecibles secrets.token_hex / token_urlsafe, y cuándo usar cada uno.
Este artículo cubre los dos módulos de números aleatorios de la biblioteca estándar. random proporciona valores pseudoaleatorios para pruebas, juegos y simulaciones (reproducibles con seed), y secrets proporciona valores impredecibles para contraseñas, tokens de restablecimiento y claves API (extraídos de la fuente aleatoria criptográfica del SO). Elegir el correcto para el trabajo es de lo que trata el resto del artículo.
Cómo difieren random y secrets
Ambos módulos devuelven números aleatorios, pero el mecanismo y los casos de uso son completamente diferentes. random está construido sobre el Mersenne Twister (un generador pseudoaleatorio ampliamente usado), y llamar a random.seed(valor) te permite reproducir la misma secuencia. secrets, por otro lado, extrae de la fuente aleatoria criptográfica del SO (como /dev/urandom), así que no hay concepto de seed y los valores son impredecibles en cada llamada.
Para casos como pruebas o juegos — «no pasa nada si el resultado se filtra» — usa random. Para contraseñas, tokens e ID de sesión — «si alguien predice el valor, tienes un incidente de seguridad» — usa secrets.
| Aspecto | random | secrets |
|---|---|---|
| Fuente | Mersenne Twister (algoritmo) | Fuente cripto del SO (/dev/urandom, etc.) |
| Reproducibilidad | Misma secuencia reproducible con seed | No reproducible (siempre diferente) |
| Velocidad | Rápido | Más lento (no es problema para el uso típico) |
| Mejor uso | Pruebas, juegos, simulaciones | Tokens, contraseñas, ID de sesión |
random — Lo básico (randint / uniform / choice)
Lo básico de random son tres cosas: un entero aleatorio / un float aleatorio / elegir un elemento de una lista. random.randint(min, max) devuelve un entero incluyendo ambos extremos, random.uniform(min, max) devuelve un float en el rango dado, y random.choice(lista) devuelve un elemento de la lista.
Empecemos sin seed y veamos cómo se comportan estas funciones básicas.
| Función | Retorno | Uso típico |
|---|---|---|
| random.randint(a, b) | Entero en [a, b] (ambos extremos incluidos) | Tiradas de dados, ID de prueba |
| random.uniform(a, b) | Float en [a, b] | Ruido, simulaciones probabilísticas |
| random.choice(seq) | Un elemento de la secuencia | Elegir un ítem de un menú |
random — Reproducibilidad por seed y operaciones sobre colecciones
Veamos ahora la reproducibilidad de pruebas con random.seed y las funciones de operación sobre colecciones (shuffle / sample). Después de llamar random.seed(N), la misma semilla siempre produce la misma secuencia. random.shuffle(lista) mezcla los elementos de la lista en su lugar, y random.sample(lista, k) devuelve una nueva lista de k elementos únicos extraídos de ella.
| Función | Retorno | Uso típico |
|---|---|---|
| random.seed(value) | None (inicializa el estado interno) | Pruebas reproducibles |
| random.shuffle(seq) | None (mezcla la lista original) | Aleatorizar el orden de una lista |
| random.sample(seq, k) | Nueva lista de k elementos únicos | Sortear k respondedores de una encuesta |
secrets — Aleatoriedad fuerte para seguridad
El módulo random de las secciones anteriores es un generador pseudoaleatorio para pruebas — si su estado interno se filtra, los siguientes valores pueden predecirse. Para cosas como tokens de restablecimiento de contraseña, claves API e ID de sesión — «si un atacante puede predecir el valor, tienes una vulnerabilidad» — elige el módulo secrets, que usa la fuente aleatoria criptográfica del SO.
secrets tiene una API mucho más pequeña que random — son sobre todo helpers que convierten bytes aleatorios en cadenas hex o URL-safe.
| Función | Retorno | Uso típico |
|---|---|---|
| secrets.token_bytes(n) | n bytes aleatorios | Claves cripto, tokens binarios internos |
| secrets.token_hex(n) | Cadena hex de longitud 2*n | ID de sesión de inicio |
| secrets.token_urlsafe(n) | Cadena URL-safe (estilo Base64) | Para incrustar en URLs de restablecimiento |
| secrets.choice(seq) | Un elemento de seq, criptográficamente | Cuando el orden de presentación no debe ser predecible |
| secrets.compare_digest(a, b) | True / False (resistente a ataques de tiempo) | Comparación de hash / token (usar en lugar de ==) |
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Después de llamar random.seed(42) y luego random.randint(1, 100), ¿qué pasa si haces lo mismo otra vez?
Pregunta 3¿Cuál es la mejor opción cuando quieres que una lista mezclada aleatoriamente sea reproducible para pruebas?