Módulo secrets en Python: números y tokens seguros

Publicado el: 11/07/2026
Tempo de leitura: 5 minutos
Geração de números aleatórios seguros usando secrets em Python

El módulo secrets de Python genera valores aleatorios adecuados para contraseñas, tokens, enlaces de recuperación, claves temporales e identificadores que no deberían ser predecibles. Está incluido en la biblioteca estándar y utiliza la fuente de entropía proporcionada por el sistema operativo. Para seguridad, esta diferencia es esencial: el módulo random fue diseñado para simulaciones y juegos, no para proteger cuentas.

Si necesitas aleatoriedad común para ejemplos, sorteos o datos reproducibles, consulta la guía del módulo random en Python. Para credenciales o tokens, utiliza secrets.

Por qué random no sirve para seguridad

random implementa un generador seudoaleatorio determinista. Si un atacante conoce o deduce el estado interno, puede predecir valores posteriores. Esto no representa un problema al mezclar una lista de preguntas, pero sí al crear un token de inicio de sesión.

import random

# No usar para seguridad
token_inseguro = random.randint(100000, 999999)
print(token_inseguro)

El módulo secrets obtiene aleatoriedad del sistema:

import secrets

token_seguro = secrets.randbelow(900000) + 100000
print(token_seguro)

Aun así, un código de seis dígitos tiene solo un millón de combinaciones. Debe tener caducidad, límite de intentos y protección contra abuso.

Generar enteros seguros con randbelow()

import secrets

indice = secrets.randbelow(10)
print(indice)  # valor entre 0 y 9

randbelow(n) devuelve un entero entre cero y n - 1. Es útil para seleccionar posiciones o construir códigos dentro de un rango definido.

Elegir un elemento con choice()

import secrets

colores = ["rojo", "verde", "azul", "negro"]
elegido = secrets.choice(colores)
print(elegido)

La función se parece a random.choice(), pero usa una fuente segura. Para generar contraseñas, define un alfabeto explícito.

Crear una contraseña aleatoria

import secrets
import string

alfabeto = string.ascii_letters + string.digits + "!@#$%&*"
longitud = 20

contrasena = "".join(secrets.choice(alfabeto) for _ in range(longitud))
print(contrasena)

Una contraseña larga y aleatoria suele ser más resistente que una corta con reglas complejas. Sin embargo, una política puede exigir al menos un carácter de cada grupo. Puedes validar y repetir la generación:

def crear_contrasena(longitud: int = 20) -> str:
    if longitud < 16:
        raise ValueError("La longitud mínima debe ser 16")

    alfabeto = string.ascii_letters + string.digits + "!@#$%&*"
    while True:
        valor = "".join(secrets.choice(alfabeto) for _ in range(longitud))
        if (
            any(c.islower() for c in valor)
            and any(c.isupper() for c in valor)
            and any(c.isdigit() for c in valor)
            and any(c in "!@#$%&*" for c in valor)
        ):
            return valor

La guía para crear un generador seguro de contraseñas en Python desarrolla este proyecto con opciones de terminal y pruebas.

Generar tokens binarios

import secrets

datos = secrets.token_bytes(32)
print(datos)

token_bytes() devuelve bytes aleatorios. Resulta apropiado cuando una biblioteca criptográfica espera una secuencia binaria. No conviertas estos bytes manualmente a texto usando codificaciones ambiguas; utiliza las funciones hexadecimales o URL-safe.

Tokens hexadecimales

token = secrets.token_hex(32)
print(token)

El argumento indica la cantidad de bytes aleatorios. La representación hexadecimal utiliza dos caracteres por byte, por lo que 32 bytes generan una cadena de 64 caracteres.

Tokens seguros para URLs

token = secrets.token_urlsafe(32)
enlace = f"https://example.com/restablecer?token={token}"
print(enlace)

token_urlsafe() produce texto compatible con URLs. Es una opción práctica para confirmación de correo, recuperación de contraseña y enlaces temporales. El token debe almacenarse de forma segura, tener fecha de expiración y ser de un solo uso.

No guardar tokens sensibles en texto plano

Si un token permite ejecutar una acción crítica, considera almacenar solo un hash del token en la base de datos. Cuando el usuario presenta el valor original, calculas su hash y comparas.

import hashlib
import secrets

original = secrets.token_urlsafe(32)
resumen = hashlib.sha256(original.encode("utf-8")).hexdigest()

# Guardar resumen, enviar original al usuario
print(original)
print(resumen)

Si la base de datos se filtra, el atacante no obtiene directamente el token válido. No confundas este patrón con el almacenamiento de contraseñas: para contraseñas se necesitan algoritmos lentos especializados como bcrypt, Argon2 o scrypt. Consulta la guía de bcrypt en Python.

Comparar valores con compare_digest()

import secrets

esperado = "abc123"
recibido = "abc123"

if secrets.compare_digest(esperado, recibido):
    print("Coinciden")

compare_digest() reduce filtraciones relacionadas con diferencias de tiempo en comparaciones de secretos. Debes comparar valores del mismo tipo y longitud razonable.

Crear un código temporal

import secrets
from datetime import datetime, timedelta, timezone

codigo = f"{secrets.randbelow(1_000_000):06d}"
expira = datetime.now(timezone.utc) + timedelta(minutes=10)

print(codigo, expira)

La seguridad no depende únicamente de la generación. Limita intentos, registra eventos, invalida el código después de usarlo y evita revelar si una cuenta existe.

Gestionar secretos de aplicación

No uses secrets para generar una clave nueva cada vez que inicia una aplicación si necesitas descifrar datos antiguos o mantener sesiones. Genera la clave una vez y almacénala fuera del código, por ejemplo en variables de entorno o un gestor de secretos.

La guía de variables de entorno en Python explica cómo separar configuración y código. Para producción, un servicio especializado ofrece rotación, auditoría y controles de acceso superiores a un archivo .env.

Generar identificadores

Los tokens aleatorios pueden servir como identificadores difíciles de adivinar:

identificador = secrets.token_urlsafe(18)
print(identificador)

No obstante, para claves internas también existen UUID. La decisión depende de longitud, formato, distribución y requisitos de seguridad. No utilices identificadores secuenciales en URLs sensibles sin autorización adicional.

Pruebas y reproducibilidad

La seguridad de secrets implica que no puedes establecer una semilla para repetir exactamente una secuencia. En pruebas, separa la generación mediante una función inyectable:

def crear_codigo(generador=secrets.randbelow):
    return f"{generador(1_000_000):06d}"

Durante el test puedes pasar una función controlada. No sustituyas secrets por random en producción solo para facilitar pruebas.

Aplicación en un gestor de contraseñas

Un gestor puede usar secrets para generar credenciales nuevas, pero la protección del archivo requiere cifrado autenticado, una clave derivada correctamente y un diseño seguro. La guía para crear un gestor de contraseñas en Python muestra un ejemplo educativo y sus limitaciones.

Errores frecuentes

Los errores habituales son generar tokens demasiado cortos, usar códigos sin límite de intentos, guardar secretos en logs, incluir tokens en repositorios, reutilizar valores, comparar con == en contextos sensibles y asumir que un valor aleatorio sustituye la autorización.

También es peligroso enviar tokens en URLs que quedan registrados en historiales, analítica o encabezados Referer. Evalúa el canal, la duración y el alcance de cada secreto.

Fuentes confiables

La documentación oficial del módulo secrets explica cada función y la elección del número de bytes. Las recomendaciones de OWASP para recuperación de contraseñas cubren tokens, expiración, uso único, límites y respuestas seguras.

Conclusión

Utiliza secrets siempre que la imprevisibilidad proteja una cuenta, sesión o acción. randbelow(), choice(), token_hex() y token_urlsafe() cubren la mayoría de necesidades. La generación es solo una parte: almacenamiento, caducidad, comparación, límites de intentos y autorización completan el diseño seguro.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Uso do operador walrus para atribuições inline em Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Operador walrus en Python: guía con ejemplos

    Aprende el operador walrus := en Python: condiciones, while, comprensiones, lectura por bloques, regex, alcance y buenas prácticas.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Uso da função zip para combinar listas em Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    zip() en Python: combina listas e iterables correctamente

    Aprende zip() en Python para combinar listas, crear diccionarios, usar strict, zip_longest, desempaquetar valores y evitar pérdidas silenciosas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Uso do módulo time para controlar tempo em scripts Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Módulo time en Python: pausas, timestamps y rendimiento

    Aprende el módulo time en Python: timestamps, sleep, monotonic, perf_counter, struct_time, strftime y buenas prácticas para medir tiempo.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Introdução ao módulo sys para iniciantes em Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Módulo sys en Python: guía práctica para principiantes

    Aprende el módulo sys en Python: argv, exit, version, platform, path, flujos estándar, tamaño de objetos y buenas prácticas.

    Ler mais

    Tempo de leitura: 6 minutos
    11/07/2026
    Como converter código Python para C usando Cython
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Cython: cómo acelerar Python compilando a C

    Aprende Cython para acelerar Python: archivos .pyx, cdef, cpdef, tipos C, memoryviews, GIL, NumPy, compilación y benchmarks.

    Ler mais

    Tempo de leitura: 6 minutos
    11/07/2026
    Uso do operador ternário em Python para condições rápidas
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Operador ternario en Python: guía clara y práctica

    Aprende el operador ternario en Python: sintaxis, asignaciones, listas, return, anidación, errores frecuentes y buenas prácticas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026