python secrets 模块
secrets 说明
secrets 模块用于生成高度加密的随机数,适于管理密码、账户验证、安全凭据及机密数据。
生成随机数
secrets 模块是操作系统提供的最安全地随机性来源。
choice(sequence)
从非空序列中返回一个安全的随机元素。
import secrets
# 假设我们有一个元素列表
elements = ['apple', 'banana', 'cherry', 'date']
# 使用 secrets.choice 来安全地选择列表中的一个随机元素
secure_random_element = secrets.choice(elements)
print(secure_random_element)
randbelow(n)
返回 [0, n) 范围内的随机整数。
import secrets
# 设定上界
n = 100
# 生成一个从0到99(包括)的随机整数
random_number = secrets.randbelow(n)
print(random_number)
randbits(k)
返回 k 个随机比特位的整数。
import secrets
# 生成一个8比特长度的随机整数
random_bits = secrets.randbits(8)
print("随机比特数:", random_bits)
class secrets.SystemRandom
用操作系统提供的最高质量源生成随机数的类。
类的主要方法:
getrandbits(k):生成一个k比特长度的随机整数。
randrange(start, stop):生成一个介于start到stop之间的随机整数。
import secrets
# 创建SystemRandom实例
sys_random = secrets.SystemRandom()
# 生成一个8比特长度的随机整数
random_bits = sys_random.getrandbits(8)
print("随机比特数:", random_bits)
# 生成一个1到10之间的随机整数
random_int = sys_random.randrange(1, 11)
print("随机整数:", random_int)
生成 Token
secrets 模块提供了生成安全 Token 的函数,适用于密码重置、密保 URL 等应用场景。
token_bytes([nbytes=None])
如果指定了 nbytes, secrets.token_bytes(nbytes) 会返回一个包含 nbytes 个随机字节的 bytes 对象。
如果未提供 nbytes 参数,它会返回一个合适用于安全令牌的默认长度的随机字节序列(通常为 32 个字节)。
import secrets
# 生成默认长度(通常为32个字节)的随机字节序列
random_token = secrets.token_bytes()
print(len(random_token)) # 输出:32
print(random_token) # 输出随机字节序列:b'\x8b\xf9\xfe#J\xffHe\x1a\xc5X\x8d1\x14\xff\x99\xba\n\xef9\x98"\xec\xb7\xbb\xfb\x9d0\x0c\xa6\xe1S'
# 生成指定长度的随机字节序列
specified_length_token = secrets.token_bytes(16)
print(specified_length_token) # 输出随机字节序列:b'\x1d\xce\xfc\x04\xc7FT\xfb\xe6\xa7T\xcb\x90\xa0n\x83'
token_hex([nbytes=None])
如果提供了 nbytes 参数,则会生成长度为 nbytes*2 的十六进制字符串(每个字节转换为两个十六进制字符)。
如果未提供 nbytes 参数,则会生成一个适用于安全令牌的默认长度的十六进制字符串(通常是 32 个字符)。
import secrets
# 生成默认长度(通常为32个字符)的随机十六进制字符串
random_hex_token = secrets.token_hex()
print(random_hex_token)
# 生成指定长度的随机十六进制字符串
specified_length_hex_token = secrets.token_hex(16)
print(specified_length_hex_token)
token_urlsafe([nbytes=None])
返回安全的 URL 随机文本字符串,包含 nbytes 个随机字节。文本用 Base64 编码,平均来说,每个字节对应 1.3 个结果字符。
未提供 nbytes 或为 None 时,它会生成一个适合于安全令牌的默认长度随机 URL 安全字符串。
这个函数生成的返回值是一个只包含 URL 安全字符(字母、数字、下划线和短横线)的字符串。
import secrets
# 生成默认长度的随机 URL 安全字符串
random_urlsafe_token = secrets.token_urlsafe()
print(len(random_urlsafe_token)) # 输出:43
print(random_urlsafe_token) # 输出:L8kP_F_Er-gLrGO_e_JHZBaZjlqXikrqfZFR-NBUSFI
# 生成指定长度的随机 URL 安全字符串
specified_length_urlsafe_token = secrets.token_urlsafe(16)
print(specified_length_urlsafe_token) # 输出:CzlTfna4b2MaRPsJWoQQbg
比较操作
compare_digest(a, b)
用于比较两个字符串 a 和 b,并且在字符串匹配时具有防止时间侧信道攻击的特性。在密码学和安全相关的场景中,比较两个敏感字符串时,使用 secrets.compare_digest 要优于简单的 == 操作符。
该函数返回一个布尔值,如果 a 和 b 匹配,返回 True,否则返回 False。这种比较在比较时间上更加均匀,不易受到时间侧信道攻击的影响。在比较敏感数据时,尤其是在密码验证或令牌比对时使用这个函数,可以提高系统的安全性。
import secrets
a = "my-secret-token-1"
b = "my-secret-token-2"
result = secrets.compare_digest(a, b)
print(result) # 如果a和b匹配,结果为True;否则为False
生成系统密码示例
import string
import random
import secrets
def generate_password(min_length, max_repeat, max_class_repeat, *char_credits):
characters = [string.digits, string.ascii_uppercase, '!@#$%^&*(){}<>,?`~+-=[]', string.ascii_lowercase]
all_characters = ''.join(characters)
while True:
# 生成每个字符类别的字符
password = [secrets.choice(char) for char, count in zip(characters, char_credits) for _ in range(count)]
# 添加字符以满足最小密码长度要求
remaining_len = min_length - sum(char_credits)
password += [secrets.choice(all_characters) for _ in range(remaining_len)]
random.shuffle(password)
if is_valid_password(min_length, password, characters, max_repeat, max_class_repeat):
return ''.join(password)
def is_valid_password(min_length, password, characters, max_repeat, max_class_repeat):
# 判断是否以=开头
if ''.join(password).startswith("="):
return False
# 检查字符和类别是否连续重复超过了规定次数
repeat_count = max(password.count(char) for char in set(password))
if repeat_count > min_length // 4:
return False
for char_class in characters:
char_class_positions = [idx for idx, char in enumerate(password) if char in char_class]
for idx in char_class_positions:
if idx < len(password) - max_class_repeat:
if all(password[idx + i] in char_class for i in range(0, max_class_repeat + 1)):
return False
# 判定同一个字符的索引
char_repeat = [char for char in set(password) if password.count(char) > max_repeat]
char_repeat_positions = {}
for idx, char in enumerate(password):
if char in char_repeat:
if char not in char_repeat_positions:
char_repeat_positions[char] = [idx]
else:
char_repeat_positions[char].append(idx)
# 判定相同字符是否连续
for _, index in char_repeat_positions.items():
for idx in index:
if idx < len(password) - max_repeat:
if all(password[idx + i] == password[idx] for i in range(0, max_repeat + 1)):
return False
return True
if __name__ == '__main__':
# 设置密码生成的参数
min_length = 16
char_credits = (3, 3, 3, 3) # 数字、大写字母、特殊字符、小写字母
# 同一个字符不能连续重复的数量
max_repeat = 2
# 同一类字符不能连续重复的数量
max_class_repeat = 3
# 生成和打印密码
for _ in range(100):
generated_password = generate_password(min_length, max_repeat, max_class_repeat, *char_credits)
print(generated_password)
生成密码重置URL示例
import secrets
import string
# 生成安全令牌,用于密码恢复应用程序
security_token = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(16))
# 构建临时密保URL
temp_url = f"https://example.com/password-recovery?token={security_token}"
print("生成的临时密保URL:", temp_url)
# 输出:生成的临时密保URL: https://example.com/password-recovery?token=Z8eiGfzhCCBQPmIS
参考文档
https://docs.python.org/zh-cn/3.12/library/secrets.html#module-secrets