应使用 secrets 而非 random 生成密码,因 random 是伪随机、种子可预测,不满足安全需求;secrets 基于操作系统密码学安全随机源,适用于密钥、令牌等场景。

为什么不用 random 生成密码
因为 random 模块用的是伪随机数生成器(PRNG),种子可预测、不抗重放,不适合安全场景。比如用 random.choice() 拼密码,攻击者在知道运行时间或进程ID时可能复现整个序列。
真实需求是「密码用于登录、API密钥、临时令牌」——这类必须用密码学安全的随机源,Python 3.6+ 的 secrets 就是为此设计的。
-
secrets底层调用操作系统级安全随机源(如 Linux 的/dev/urandom,Windows 的CryptGenRandom) -
random适合模拟、抽样;secrets才适合生成密钥、密码、token - 即使加了
random.seed(int(time.time())),也毫无意义——这不是增强安全性,是制造虚假安全感
secrets.choice() 和 secrets.token_urlsafe() 怎么选
取决于你对「密码格式」有没有硬性要求。
secrets.choice() 给你最大控制权:自己定义字符集、长度、是否允许重复、是否强制包含大小写数字符号;secrets.token_urlsafe() 省事但格式固定(base64url 编码,含 a-z A-Z 0-9 - _,无歧义字符,适合 URL 或文件名场景)。
- 要兼容老系统(比如只接受纯数字+大写字母)?必须用
secrets.choice()搭配自定义字符表 - 生成一次性访问链接里的 token?
secrets.token_urlsafe(16)直接可用,长度参数是字节长度,实际字符串约长 22 位 - 注意:
secrets.token_urlsafe(n)的n是字节数,不是字符数;而secrets.choice()循环调用次数才是最终密码长度
避免常见拼错和逻辑漏洞
写的时候容易手快打成 secret(少个 s),或者误用 secrets.randbelow() 做索引越界——它返回 [0, n),但如果你字符表长度是 64,却传 65,不会报错,但会漏掉最后一个字符。
- 字符表别写错:
"ABCDEFGHJKLMNPQRSTUVWXYZ23456789"(跳过易混淆字符 O/0/I/l/1)是常见做法,别漏掉引号或拼错字母 - 别用
secrets.randbits(8)自己转字符——没这个必要,还容易出编码错误 - 生成后别直接 print 到日志里;如果真要调试,至少用
repr(pwd)避免不可见字符干扰判断 - 别把密码明文存进 Git:哪怕只是测试脚本,也该用环境变量或临时禁用提交(
.gitignore或git update-index --skip-worktree)
生成带规则的密码(比如必须含大小写+数字+符号)
不能靠「全量随机再校验」——万一连续几百次都不满足条件,会卡住(虽然概率极低,但逻辑上不健壮)。应该先确保每类至少取一个,再补足剩余长度。
例如要 12 位密码,且必须含大小写字母、数字、符号各至少一个:
import secrets
import string
<p>def gen_strong_password(length=12):
if length = 4")
lower = secrets.choice(string.ascii_lowercase)
upper = secrets.choice(string.ascii_uppercase)
digit = secrets.choice(string.digits)
punct = secrets.choice("!@#$%^&*")</p><h1>剩余位置从全集里选</h1><pre class="brush:python;toolbar:false;">all_chars = string.ascii_letters + string.digits + "!@#$%^&*"
rest = ''.join(secrets.choice(all_chars) for _ in range(length - 4))
# 打乱顺序(避免固定模式)
pwd_list = list(lower + upper + digit + punct + rest)
secrets.SystemRandom().shuffle(pwd_list)
return ''.join(pwd_list)
关键点:用 secrets.SystemRandom().shuffle(),而不是 random.shuffle()——前者才是密码学安全的打乱。
真正难的不是生成,而是后续怎么安全地交付、存储、轮换。比如发给用户邮件?得确认 SMTP 连接是 TLS 加密的;存数据库?字段得加密,别裸存。这些比「怎么生成」更值得花时间检查。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











