文章目录

Python 随机数:random 模块与 secrets 模块

发布于 2026-04-04 02:07:07 · 浏览 2 次 · 评论 0 条

Python 随机数:random 模块与 secrets 模块

Python 提供了两种生成随机数的方式:random 模块和 secrets 模块。它们用途不同,安全性也不同。不要混淆使用场景——日常模拟用 random,密码、令牌等安全敏感数据必须用 secrets


1. random 模块:用于模拟和非安全场景

random 模块基于伪随机数生成器(PRNG),速度快但可预测。只要知道初始种子(seed),就能复现整个随机序列。因此它适用于游戏、抽样、仿真等不需要保密的场合。

基本用法

导入 random 模块:

import random

生成 0 到 1 之间的浮点数

x = random.random()  # 返回 [0.0, 1.0) 范围内的数

生成指定范围的整数

n = random.randint(1, 10)  # 返回 1 到 10(含)之间的整数

从列表中随机选择一个元素

items = ['apple', 'banana', 'cherry']
choice = random.choice(items)

打乱列表顺序(原地修改)

deck = [1, 2, 3, 4, 5]
random.shuffle(deck)  # deck 变为随机顺序

设置种子以复现结果

random.seed(42)  # 设置固定种子
print(random.random())  # 每次运行都输出相同的数

⚠️ 警告random 模块生成的数不能用于加密、密码、安全令牌等场景。攻击者可通过观察部分输出推测内部状态,进而预测后续值。


2. secrets 模块:用于安全敏感场景

secrets 模块从操作系统提供的加密安全随机源(如 /dev/urandom 或 Windows CryptoAPI)获取随机数,不可预测且抗攻击。适用于生成密码、API 密钥、一次性令牌等。

基本用法

导入 secrets 模块(Python 3.6+ 内置):

import secrets

生成安全的随机整数

n = secrets.randbelow(100)  # 返回 [0, 100) 范围内的整数

生成指定比特长度的随机整数

k = secrets.randbits(128)  # 返回一个 128 位的随机整数

从序列中安全地选择一个元素

choices = ['admin', 'user', 'guest']
role = secrets.choice(choices)

生成 URL 安全的随机令牌

token = secrets.token_urlsafe(32)  # 生成 32 字节的 Base64 编码字符串,适合用作会话 ID

生成十六进制格式的随机字符串

hex_token = secrets.token_hex(16)  # 生成 32 字符长的十六进制字符串(16 字节)

最佳实践:只要涉及用户凭证、重置链接、API 密钥等,一律使用 secrets


3. 关键区别对比

以下表格总结了两个模块的核心差异:

特性 random 模块 secrets 模块
随机源 伪随机算法(Mersenne Twister) 操作系统加密安全随机源
可预测性 是(已知种子可复现) 否(不可预测)
性能 稍慢(但对多数应用无感)
适用场景 模拟、游戏、抽样 密码、令牌、密钥、安全 ID
是否支持设置种子
Python 最低版本 所有版本 3.6+

4. 常见错误与正确做法

错误:用 random 生成密码重置链接

# ❌ 危险!不要这样做
import random
reset_code = ''.join(random.choices('0123456789', k=6))

攻击者可能通过多次请求分析模式,甚至暴力破解。

正确:用 secrets 生成安全令牌

# ✅ 安全做法
import secrets
reset_token = secrets.token_urlsafe(32)

该令牌足够随机,无法被预测或碰撞。

错误:用 random.shuffle 打乱敏感数据顺序并认为“安全”

即使顺序被打乱,若攻击者知道算法和部分输入,仍可能逆推。

正确:仅在非安全上下文中使用 random.shuffle

例如洗牌游戏可以,但用户权限列表的随机分配若涉及安全策略,则应避免依赖随机性做访问控制。


5. 实用示例:生成强密码

使用 secretsstring 模块组合生成符合安全要求的密码

import secrets
import string

def generate_password(length=12):
    alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
    while True:
        password = ''.join(secrets.choice(alphabet) for _ in range(length))
        # 确保至少包含一个小写字母、大写字母、数字和特殊字符
        if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and any(c.isdigit() for c in password)
            and any(c in "!@#$%^&*" for c in password)):
            return password

pwd = generate_password(16)
print(pwd)

此函数保证密码强度,且使用加密安全的随机源。


6. 总结判断流程

当你需要生成随机数时,按以下逻辑决策:

  1. 是否用于安全目的?(如密码、密钥、认证令牌)
    • 是 → 必须用 secrets
    • 否 → 进入下一步
  2. 是否需要复现实验结果?(如科研模拟、测试)
    • 是 → random 并设置 seed
    • 否 → 仍可用 random,但无需设种子

永远不要为了“方便”而在安全场景使用 random。多写一行 import secrets,换来的是系统安全的根本保障。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文