现有的答案很好,但我只是补充几点。
更新:
实际上,如果您不提供种子,则随机数生成器会使用来自系统随机源的随机位作为种子,如果操作系统没有随机数,它只会回退到使用系统时间作为种子资源。另请注意,最新版本的 Python 可以使用改进的播种方案。来自the docs:
random.seed(a=None, version=2)
初始化随机数生成器。
如果省略a 或None,则使用当前系统时间。如果
随机源由操作系统提供,它们用于
而不是系统时间(请参阅os.urandom() 函数
可用性的详细信息)。
如果a是一个int,则直接使用。
对于版本 2(默认),str、bytes 或 bytearray 对象获取
转换为 int 并使用其所有位。
使用版本 1(提供用于从旧版本复制随机序列
Python 版本),str 和 bytes 的算法会生成一个
种子范围更窄。
在 3.2 版中更改:移至使用字符串种子中的所有位的版本 2 方案。
与生成加密密钥(尤其是打算多次使用的密钥)相比,生成验证码并不是一种高安全性应用程序。因此,生成 CAPTCHA 代码所需的熵量小于加密密钥所需的熵。
请记住,用于播种 random 的系统时间(可能)不是以秒为单位的系统时间 - 它更可能是以微秒甚至纳秒为单位的时间,因此攻击者不容易计算除了 Ned 提到的考虑因素之外,从蛮力搜索中取出种子。
这是一个快速演示,在 2GHz Linux 系统上运行 Python 2.6.6。
#!/usr/bin/env python
''' random seeding demo'''
from __future__ import print_function
import time
from random import seed, randint, random
def rf():
return randint(10, 99)
def put_time():
print('%.15f' % time.time())
r = range(10)
a = []
put_time()
for i in r:
seed()
a.append([rf() for j in r])
put_time()
for row in a:
print(row)
典型输出
1436617059.071794986724854
1436617059.074091911315918
[95, 25, 50, 75, 80, 38, 21, 26, 85, 82]
[75, 96, 14, 13, 76, 53, 94, 68, 80, 66]
[79, 33, 65, 86, 12, 32, 80, 83, 36, 42]
[28, 47, 62, 21, 52, 30, 54, 62, 22, 28]
[22, 40, 71, 36, 78, 64, 17, 33, 99, 43]
[81, 15, 32, 15, 63, 57, 83, 67, 12, 62]
[22, 56, 54, 55, 51, 56, 34, 56, 94, 16]
[64, 82, 37, 80, 70, 91, 56, 41, 55, 12]
[47, 37, 64, 14, 69, 65, 42, 17, 22, 17]
[43, 43, 73, 82, 61, 55, 32, 52, 86, 74]
如您所见,外循环开始和结束之间的时间不到 3 毫秒,但 a 中的所有列表都完全不同。
请注意,传递给random.seed() 的种子可以是任何可散列的对象,当你传递一个非整数(例如float 像系统时间)时,它首先被散列以创建一个整数。
不过,没有必要仅仅使用系统时间作为种子:您可以使用SystemRandom / os.urandom() 来获取种子。那样的话,种子更不可预测,但你得到梅森捻线机的速度; SystemRandom 比 Mersenne Twister 慢一点,因为它必须进行系统调用。然而,即使urandom 也不是完全安全的。
来自 GNU urandom man page:
随机数生成器从设备收集环境噪声
驱动程序和其他来源进入熵池。发电机也
保持对熵池中噪声位数的估计。
从这个熵池中创建随机数。
读取时,/dev/random 设备将只返回随机字节
在熵池中估计的噪声位数之内。
/dev/random 应该适合需要非常高质量的用途
随机性,例如一次性填充或密钥生成。当熵
池为空,从 /dev/random 读取将阻塞,直到额外
收集环境噪音。
从 /dev/urandom 设备读取不会阻塞等待更多
熵。因此,如果没有足够的熵
熵池,返回值理论上容易受到
对驱动程序使用的算法的加密攻击。知识
如何做到这一点在当前未分类中不可用
文献,但从理论上讲,这种攻击可能
存在。如果这是您的应用程序中的一个问题,请使用 /dev/random
而是。
用法
如果您不确定是否应该使用
/dev/random 或 /dev/urandom,那么您可能想使用后者。
作为一般规则,/dev/urandom 应该用于除
长期存在的 GPG/SSL/SSH 密钥。
有关为什么 /dev/urandom 几乎总是比 /dev/random 更可取的更多信息,请参阅Myths about /dev/urandom。