我正在阅读标准库中有关python的随机模块。令我惊讶的是,当我设置种子并产生一些随机数时:
random.seed(1)
for i in range(5):
print random.random()
产生的数字与文章中的样本完全相同。我认为可以肯定地说,当种子设定时,算法是确定性的。
当未设置种子时,标准库种子为time.time()
。
现在假设在线服务使用random.random()
生成验证码,黑客是否可以使用相同的随机生成器轻松再现验证码?
我是否担心太多,或者这是一个真正的漏洞?
答案 0 :(得分:6)
播种后序列是确定性的,这不应该让你感到惊讶。这就是播种的重点。 random.random
被称为PRNG,伪 - 随机数生成器。这不是Python独有的,每种语言的简单随机源都是以这种方式确定的。
是的,真正关心安全性的人会担心攻击者可以重现序列。这就是为什么其他随机源可用,如os.urandom
,但它们更贵。
但问题并不像你说的那么糟糕:对于Web请求,通常一个进程处理多个请求,因此模块在过去的某个未知点初始化,而不是在收到Web请求时。< / p>
答案 1 :(得分:6)
现有答案很棒,但我只想补充几点。
<强>更新强>
实际上,如果你不提供种子,那么随机数生成器会从系统随机源中随机位进行播种,如果操作系统没有随机数,它只会回退到使用系统时间作为种子资源。另请注意,最新版本的Python可以使用改进的种子方案。来自the docs:
random.seed(a =无,版本= 2)
初始化随机数生成器。
如果省略
a
或None
,则使用当前系统时间。如果 随机源由操作系统提供,它们被使用 而不是系统时间(参见os.urandom()
函数 可用性详情。如果
a
是int,则直接使用。使用版本2(默认值),str,bytes或bytearray对象获取 转换为int并使用它的所有位。
使用版本1(用于从旧版本中再现随机序列) Python的版本,str和bytes的算法生成一个 种子范围较窄。
在版本3.2中更改:已移至版本2方案,该方案使用字符串种子中的所有位。
生成CAPTCHA代码并不是一种高安全性的应用程序,而是生成秘密加密密钥,尤其是旨在多次使用的密钥。作为推论,生成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()
来获取种子。这样,种子更难以预测,但你获得了Mersenne Twister的速度; 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密钥。
答案 2 :(得分:5)
几乎所有模块函数都依赖于函数random(),它在半开放范围[0.0,1.0]内均匀生成随机浮点数。 Python使用Mersenne Twister作为核心生成器。它产生53位精度浮点数,周期为2 ** 19937-1。 C中的底层实现既快又线程安全。 Mersenne Twister是现存最广泛测试的随机数发生器之一。但是,完全确定性,它不适合所有目的,并且完全不适合加密目的。
有关安全随机的信息,请参阅this answer。
答案 3 :(得分:4)
Python documentation有这样说:
警告强> 不应使用此模块的伪随机生成器 安全目的。如果需要,请使用os.urandom()或SystemRandom 加密安全的伪随机数发生器。
因此,将它用于CAPTCHA可能不是一个好主意。