secrets
—- 生成管理密码的安全随机数
3.6 新版功能.
源代码: Lib/secrets.py
secrets
模块用于生成高度加密的随机数,适于管理密码、账户验证、安全凭据及机密数据。
最好用 secrets
替代 random
模块的默认伪随机数生成器,该生成器适用于建模和模拟,不宜用于安全与加密。
参见
随机数
secrets
模块是操作系统提供的最安全地随机性来源。
class secrets.SystemRandom
用操作系统提供的最高质量源生成随机数的类。详见 random.SystemRandom
。
secrets.choice
(sequence)
返回从非空序列中随机选取的元素。
secrets.randbelow
(n)
返回 [0, n) 范围内的随机整数。
secrets.randbits
(k)
返回 k 个随机比特位的整数。
生成 Token
secrets
模块提供了生成安全 Token 的函数,适用于密码重置、密保 URL 等应用场景。
secrets.token_bytes
([nbytes=None])
返回含 nbytes 个字节的随机字节字符串。如果未提供 nbytes,或nbytes 为 None
,则使用合理的默认值。
>>> token_bytes(16)
b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'
secrets.token_hex
([nbytes=None])
返回十六进制随机文本字符串。字符串有 nbytes 个随机字节,每个字节转换为两个十六进制数码。未提供 nbytes 或为 None
时,则使用合理的默认值。
>>> token_hex(16)
'f9bf78b9a18ce6d46a0cd2b0b86df9da'
secrets.token_urlsafe
([nbytes=None])
返回安全的 URL 随机文本字符串,包含 nbytes 个随机字节。文本用 Base64 编码,平均来说,每个字节对应 1.3 个结果字符。未提供 nbytes 或为 None
时,则使用合理的默认值。
>>> token_urlsafe(16)
'Drmhze6EPcv0fN_81Bj-nA'
Token 应当使用多少个字节?
为了在面对 暴力攻击 时保证安全,Token 的随机性必须足够高。随着计算机推衍能力的不断提升,随机性的安全标准也要不断提高。比如 2015 年,32 字节(256 位)的随机性对于 secrets
模块的典型用例就已经足够了。
要自行管理 Token 长度的用户,可以通过为 token_*
函数指定 int
参数显式指定 Token 要使用多大的随机性。该参数以字节数表示随机性大小。
反之,如果未提供参数,或参数为 None
,则 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
# 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))
生成临时密保 URL,包含密码恢复应用的安全 Token:
import secrets
url = 'https://mydomain.com/reset=' + secrets.token_urlsafe()