secrets — Genera números aleatorios seguros para trabajar con secretos criptográficos

Nuevo en la versión 3.6.

Código fuente: Lib/secrets.py


El módulo secrets se usa para generar números aleatorios criptográficamente fuertes, apropiados para trabajar con datos como contraseñas, autenticación de cuentas, tokens de seguridad y secretos relacionados.

En particular, secrets se debe usar en lugar del generador de números pseudoaleatorios del módulo random, que está diseñado para el modelado y la simulación, no para la seguridad o la criptografía.

Ver también

PEP 506

Números aleatorios

El módulo secrets provee acceso a la fuente más segura de aleatoriedad que proporciona su sistema operativo.

class secrets.SystemRandom

Una clase para generar números aleatorios utilizando las fuentes de mayor calidad que proporciona el sistema operativo. Ver random.SystemRandom para más detalles.

secrets.choice(sequence)

Retorna un elemento aleatorio de una secuencia no vacía.

secrets.randbelow(n)

Retorna un entero aleatorio en el rango [0, n).

secrets.randbits(k)

Retorna un entero con k bits aleatorios.

Generando tokens

El módulo secrets provee funciones para generar tokens seguros, adecuados para aplicaciones como el restablecimiento de contraseñas, URLs difíciles de adivinar, y similares.

secrets.token_bytes([nbytes=None])

Retorna una cadena de bytes aleatorios que contiene nbytes número de bytes. Si nbytes es None o no se suministra, se utiliza un valor por defecto razonable.

>>> token_bytes(16)  
b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'
secrets.token_hex([nbytes=None])

Retorna una cadena de caracteres aleatoria, en hexadecimal. La cadena de caracteres tiene nbytes bytes aleatorios, cada byte convertido a dos dígitos hexadecimales. Si nbytes es None o no se suministra, se utiliza un valor por defecto razonable.

>>> token_hex(16)  
'f9bf78b9a18ce6d46a0cd2b0b86df9da'
secrets.token_urlsafe([nbytes=None])

Retorna una cadena de caracteres aleatoria para usarse en URLs, que contiene nbytes bytes aleatorios. El texto está codificado en Base64, por lo que en promedio cada byte resulta en aproximadamente 1,3 caracteres. Si nbytes es None o no se suministra, se utiliza un valor por defecto razonable.

>>> token_urlsafe(16)  
'Drmhze6EPcv0fN_81Bj-nA'

¿Cuántos bytes deben tener los tokens?

Para estar seguros contra los ataques de fuerza bruta, los tokens deben tener suficiente aleatoriedad. Desafortunadamente, lo que es considerado suficiente necesariamente aumentará a medida que las computadoras se vuelvan más potentes y capaces de hacer más pruebas en un período más corto. Desde 2015 se cree que 32 bytes (256 bits) de aleatoriedad son considerados suficientes para el típico caso de uso del módulo secrets.

Para quienes quieran gestionar la longitud de sus propios tokens, pueden especificar explícitamente cuánta aleatoriedad se utiliza para los tokens dando un argumento int a las funciones token_*. Ese argumento se toma como el número de bytes de aleatoriedad a utilizar.

En caso contrario, si no se proporciona ningún argumento, o si el argumento es None, las funciones token_* utilizarán en su lugar un valor por defecto razonable.

Nota

El valor por defecto está sujeto a cambios en cualquier momento, incluso en los lanzamientos de mantenimiento.

Otras funciones

secrets.compare_digest(a, b)

Retorna True si las cadenas de caracteres a y b son iguales, de lo contrario, False, de forma tal que se reduzca el riesgo de ataques de análisis temporal. Ver hmac.compare_digest`() para detalles adicionales.

Recetas y mejores prácticas

Esta sección muestra las recetas y las mejores prácticas para usar secrets para conseguir un nivel mínimo de seguridad.

Generar una contraseña alfanumérica de ocho caracteres:

import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))

Nota

Las aplicaciones no deben almacenar contraseñas en un formato recuperable, ya sea en texto plano o encriptado. Deberían ser saladas y hasheadas usando una función hash unidireccional (irreversible) y criptográficamente fuerte.

Generar una contraseña alfanumérica de diez caracteres con al menos un carácter en minúscula, al menos un carácter en mayúscula y al menos tres dígitos:

import string
import secrets
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(10))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break

Generar una contraseña al estilo XKCD:

import secrets
# On standard Linux systems, use a convenient dictionary file.
# Other platforms may need to provide their own word-list.
with open('/usr/share/dict/words') as f:
    words = [word.strip() for word in f]
    password = ' '.join(secrets.choice(words) for i in range(4))

Generar una URL temporal difícil de adivinar que contenga un token de seguridad adecuado para la recuperación de contraseñas:

import secrets
url = 'https://mydomain.com/reset=' + secrets.token_urlsafe()