"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.

In particular, "secrets" should be used in preference to the default
pseudo-random number generator in the "random" module, which is
designed for modelling and simulation, not security or cryptography.

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()
