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

Added in version 3.6.

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

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

"secrets" 模块用于生成高度加密的随机数，适于管理密码、账户验证、安全凭
据以及相关的加密数据。

具体而言，应当使用 "secrets" 来代替 "random" 模块中的默认伪随机数生成
器，后者被设计用于建模和模拟，而不宜用于安全或加密。

参见: **PEP 506**


随机数
======

"secrets" 模块提供了对你的操作系统上可用的最安全的随机性源的访问。

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)

   Return "True" if strings or *bytes-like objects* *a* and *b* are
   equal, otherwise "False", using a "constant-time compare" to reduce
   the risk of timing attacks. See "hmac.compare_digest()" for
   additional details.


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

本节展示了一些使用 "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()
