"secrets" --- 生成管理密码的安全随机数
**************************************

Added in version 3.6.

**源代码:** Lib/secrets.py

======================================================================

The "secrets" module is used for generating cryptographically strong
random numbers suitable for managing data such as passwords, account
authentication, security tokens, and related secrets.

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.

参见: **PEP 506**


随机数
======

The "secrets" module provides access to the most secure source of
randomness that your operating system provides.

class secrets.SystemRandom

   用操作系统提供的最高质量源生成随机数的类。详见
   "random.SystemRandom"。

secrets.choice(seq)

   返回一个从非空序列中随机选取的元素。

secrets.randbelow(exclusive_upper_bound)

   返回 [0, *exclusive_upper_bound*) 范围内的随机整数。

secrets.randbits(k)

   返回有 *k* 个随机比特位的非负整数。


生成 Token
==========

The "secrets" module provides functions for generating secure tokens,
suitable for applications such as password resets, hard-to-guess URLs,
and similar.

secrets.token_bytes(nbytes=None)

   Return a random byte string containing *nbytes* number of bytes.

   If *nbytes* is not specified or "None", "DEFAULT_ENTROPY" is used
   instead.

      >>> token_bytes(16)
      b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'

secrets.token_hex(nbytes=None)

   Return a random text string, in hexadecimal.  The string has
   *nbytes* random bytes, each byte converted to two hex digits.

   If *nbytes* is not specified or "None", "DEFAULT_ENTROPY" is used
   instead.

      >>> token_hex(16)
      'f9bf78b9a18ce6d46a0cd2b0b86df9da'

secrets.token_urlsafe(nbytes=None)

   Return a random URL-safe text string, containing *nbytes* random
   bytes.  The text is Base64 encoded, so on average each byte results
   in approximately 1.3 characters.

   If *nbytes* is not specified or "None", "DEFAULT_ENTROPY" is used
   instead.

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


Token 应当使用多少个字节？
--------------------------

To be secure against brute-force attacks, tokens need to have
sufficient randomness.  Unfortunately, what is considered sufficient
will necessarily increase as computers get more powerful and able to
make more guesses in a shorter period.  As of 2015, it is believed
that 32 bytes (256 bits) of randomness is sufficient for the typical
use-case expected for the "secrets" module.

要自行管理 Token 长度的用户，可以通过为 "token_*" 函数指定 "int" 参数
显式指定 Token 要使用多大的随机性。该参数以字节数表示随机性大小。

Otherwise, if no argument is provided, or if the argument is "None",
the "token_*" functions use "DEFAULT_ENTROPY" instead.

secrets.DEFAULT_ENTROPY

   "token_*" 函数所使用的默认随机字节数。

   该值可能随时发生变化，包括在维护版本发布的时候。


其他函数
========

secrets.compare_digest(a, b)

   如果字符串或 *字节型对象* *a* 与 *b* 相等则返回 "True"，否则返回
   "False"，使用了“常数时间比较”来降低 定时攻击 的风险。请参阅
   "hmac.compare_digest()" 了解更多细节。


应用技巧与最佳实践
==================

本节展示了一些使用 "secrets" 来管理基本安全级别的应用技巧和最佳实践。

生成长度为八个字符的字母数字密码：

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

备注:

  应用程序不应该 **以可恢复的格式存储密码**，无论是纯文本的还是加密的
  。 它们应当使用高加密强度的单向（不可逆）哈希函数加盐并执行哈希运算
  。

生成长度为十个字符的字母数字密码，包含至少一个小写字母，至少一个大写字
母以及至少三个数字：

   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

生成 XKCD 风格的密码串：

   import secrets
   # 在标准 Linux 系统中，使用方便的字典文件。
   # 其他系统平台可能需要提供它们专用的词列表。
   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))

生成包含安全 Token 的难以猜测的临时 URL，适用于密码恢复应用：

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