Skip to main content

15.7. secrets —生成安全的随机数用于管理秘密

3.6 新版功能.

源代码: Lib/secrets.py


secrets 模块用于生成适合于管理数据的密码强的随机数,例如密码,帐户认证,安全令牌和相关的秘密。

特别地,应当优先使用 random 模块中的 secrets 作为默认伪随机数发生器,其被设计用于建模和仿真,而不是安全性或密码学。

参见

PEP 506

15.7.1. 随机数

secrets 模块提供对操作系统提供的最安全的随机源的访问。

class secrets.SystemRandom

用于使用操作系统提供的最高质量源生成随机数的类。有关其他详细信息,请参阅 random.SystemRandom

secrets.choice(sequence)

从非空序列返回随机选择的元素。

secrets.randbelow(n)

在范围[0,n)中返回一个随机int。

secrets.randbits(k)

返回一个带有 k 随机位的整数。

15.7.2. 生成令牌

secrets 模块提供用于生成安全令牌的功能,适用于诸如密码重置,难以猜测的URL等的应用。

secrets.token_bytes([nbytes=None])

返回包含 nbytes 字节数的随机字节字符串。如果 nbytesNone 或未提供,则使用合理的默认值。

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

返回一个随机的十六进制文本字符串。该字符串具有 nbytes 随机字节,每个字节转换为两个十六进制数字。如果 nbytesNone 或未提供,则使用合理的默认值。

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

返回随机的URL安全文本字符串,其中包含 nbytes 随机字节。文本是Base64编码,因此平均每个字节导致约1.3个字符。如果 nbytesNone 或未提供,则使用合理的默认值。

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

15.7.2.1. 标记应使用多少字节?

为了抵抗 暴力攻击,令牌需要具有足够的随机性。不幸的是,当计算机变得更强大并且能够在更短的时间内做出更多的猜测时,认为足够的将必然增加。截至2015年,相信32字节(256位)的随机性对于 secrets 模块期望的典型使用情况是足够的。

对于那些想要管理自己的令牌长度的用户,可以通过为各种 token_* 函数提供 int 参数来明确指定用于令牌的随机性。该参数被视为要使用的随机字节数。

否则,如果没有提供参数,或者如果参数是 None,则 token_* 函数将使用合理的默认值。

注解

该默认值随时可能更改,包括在维护版本期间。

15.7.3. 其他功能

secrets.compare_digest(a, b)

返回 True 如果字符串 ab 相等,否则 False,以减少 定时攻击 的风险的方式。有关其他详细信息,请参阅 hmac.compare_digest()

15.7.4. 食谱和最佳做法

本节显示使用 secrets 管理基本安全级别的配方和最佳做法。

生成八个字符的字母数字密码:

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

注解

应用程序不应该是 以可恢复的格式存储密码,无论是纯文本还是加密的。它们应该使用加密强的单向(不可逆)散列函数进行加密和散列。

生成包含至少一个小写字符,至少一个大写字符和至少三个数字的十字符字母数字密码:

import string
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(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风格的密码短语

# 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(choice(words) for i in range(4))

生成包含适用于密码恢复应用程序的安全令牌的难以猜测的临时URL:

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