• 在Python中使用secrets模块生成安全随机数
  • 发布于 1周前
  • 28 热度
    1 评论
  • 朱莎莎
  • 18 粉丝 42 篇博客
  •   
Python 3.6引入了一个名叫secrets的模块,用于生成强大而安全的随机数。在本文中,我们将学习如何使用它。


随机模块提供的随机生成器是伪随机数生成器,它不具有加密安全性,因此在Python 3.6及更高版本中添加了secrets模块。

加密安全随机生成器使用同步方法生成随机数据,以确保没有两个进程可以同时获得相同的数据。

在Python 3.6之前,我们用os.urandom()和random.SystemRandom类加密地使随机数发生器安全。


注意:secrets模块仅在Python3.6以及更高的版本中可以获得。如果你正在使用Python的旧版本,而却想要使随机生成器安全,请参考:https://pynative.com/cryptographically-secure-random-data-in-python
secrets模块是CSPRNG,即加密性强伪随机数发生器(cryptographically strong Pseudo-Random Number Generator)。它被用来生成随机数,在对安全敏感的应用程序中是安全和有用的。

请参阅PEP-0506。此PEP旨在将secrets模块添加到Python标准库中。


您可以使用secrets模块来执行以下常见的安全相关功能:
1.生成随机数
2.密码和一次性密码(OTP即One Time Password)
3.随机token
4.密码恢复安全URL和会话密钥
注意:secrets模块基于os.urandom()和random.SystemRandom(), 它们是操作系统最好的加密随机性源码的接口。
在Windows上,os.urandom()在内部使用CryptGenRandom(),Linux 3.17及更新版本,getrandom()系统调用现在可以使用,在OpenBSD 5.6及更高版本中,现在使用C getentropy()函数。

下面让我们来看如何使用secrets模块。


类secrets.SystemRandom
.使用操作系统提供的最高质量源来生成随机数的类
.使用secrets.SystemRandom类我们能使用所有的random模块的功能
.在secrets模块之前,我们使用random.SystemRandom去加密地使随机数据安全。使用secrets模块也可以使用同样的类。仅需执行secrets.SystemRandom()
让我们看一下如何使用secrets.SystemRandom类来保护随机生成器的示例:
示例:
import secrets

print("Random integer number generated using secrets module is ")

number = secrets.randbelow(10)
print(number)

number = secrets.randbelow(10)
print(number)

number = secrets.randbelow(10)
print(number)

#Getting systemRandom class instance out of secrets module
secretsGenerator = secrets.SystemRandom()

#random integer number uisng secrets
randomNumber = secretsGenerator.randint(0,50)
print("Secure random number is ", randomNumber)

#random integer number within given range using secrets
randomNumber = secretsGenerator.randrange(4, 40, 4)
print("Secure random number within range is ", randomNumber)

#Secure Random choice using secrets
number_list = [6, 12, 18, 24, 30, 36, 42, 48, 54, 60]
secure_choice = secretsGenerator.choice(number_list)
print ("Secure random choice using secrets is ", secure_choice)

#Secure Random sample uisng secrets
secure_sample = secretsGenerator.sample(number_list, 3)
print ("Secure random sample using secrets is ", secure_sample)

#Secure Random uniform using secrets
secure_float = secretsGenerator.uniform(2.5, 25.5)
print("Secure random float number using secrets is ", secure_float)
输出:
Secure random number is  35
Secure random number within range is  28
Secure random choice using secrets is  54
Secure random sample using secrets is  [30, 54, 60]
Secure random float number using secrets is  11.52975639443349
Python Secrets模块的功能
Secrets模块使用底层操作系统的安全随机源。让我们看如何使用secrets模块的功能。
secrets.randbelow(n)
使用secrets.randbelow函数生成安全的整数
这个函数返回一个在[0,n)区间的安全随机整数,n是唯一的上限
0是范围的开始数字,n是最后的数字
例如,secrets.randbelow(10)将生成一个从0到10的单个随机数
示例:
import secrets

print("Random integer number generated using secrets module is ")
for i in range(3):
    print( secrets.randbelow(10), end =', ')
输出:
Random integer number generated using secrets module is 
7, 3, 2,

secrets.choice(sequence)
此方法从非空序列返回安全的随机选择元素
这里的序列可以是列表或字符串
示例:
import secrets

name = "GuidoVanRossum"
print("secrets choice from string is ", secrets.choice(name))
print("secrets choice from string is ", secrets.choice(name))

name_list = ["Guido Van Rossum", "Bjarne Stroustrup", "Dennis Ritchie"]
print("secrets choice from list is ", secrets.choice(name_list))
print("secrets choice from list is ", secrets.choice(name_list))

输出:
secrets choice from string is  o
secrets choice from string is  m
secrets choice from list is  Dennis Ritchie
secrets choice from list is  Guido Van Rossum
secrets.randbits(k)
此方法返回带有k个随机位的安全无符号整数
此函数用于生成包含N位的随机位掩码(这不同于生成随机整数,因为在这里不保证生成的数固定包含几个比特位,而是比特位由你决定)
使用randbits生成的数字更安全
它生成在给定bit范围内的随机整数
如果k=4,无符号整数从0到15
如果k=8,无符号整数从0到255
如果k=16,无符号整数从0到65535等等
示例:
import secrets

for i in range(3):
    randomBitNumber = secrets.randbits(4)
    print("Random Number using 4 bit is",randomBitNumber )

for i in range(3):
    randomBitNumber = secrets.randbits(8)
    print("Random Number using 8 bit is",randomBitNumber )

for i in range(3):
    randomBitNumber = secrets.randbits(16)
    print("Random Number using 16 bit is",randomBitNumber )

for i in range(3):
    randomBitNumber = secrets.randbits(32)
    print("Random Number using 32 bit is",randomBitNumber )
输出:
Random Number using 4 bit is 3
Random Number using 4 bit is 5
Random Number using 4 bit is 11

Random Number using 8 bit is 179
Random Number using 8 bit is 190
Random Number using 8 bit is 233

Random Number using 16 bit is 36823
Random Number using 16 bit is 24082
Random Number using 16 bit is 39181

Random Number using 32 bit is 3372867089
Random Number using 32 bit is 134143722
Random Number using 32 bit is 3810053956

使用secrets模块生成secure token
secrets模块提供用于生成secure token的功能,这对于应用程序生成reset password tokens和hard-to-guess URL是有用的。
secure 模块有如下方法生成secure token
secrets.token_bytes([nbytes=None])
返回包含字节数的安全随机字节串。如果没有提供nbytes ,则使用合理的默认值。
secrets.token_hex([nbytes=None])
返回一个十六进制格式的安全随机文本字符串。该字符串具有nbytes随机字节,每个字节转换为两个十六进制数字。如果没有提供nbytes,则使用合理的默认值。
secrets.token_urlsafe([nbytes=None])
返回一个安全的随机URL-safe文本字符串,包含nbytes随机字节。使用此方法生成安全的hard-to-guess URLs。
示例:
import secrets

print("Generate a secure byte token", secrets.token_bytes(16))

print("Generate a secure hexadecimal token", secrets.token_hex(32))

passwordResetLink = "https://pynative.com/customer/eric/reset="
passwordResetLink+=secrets.token_urlsafe(32)
print("Generate a secure URL", passwordResetLink)
输出:
Generate a secure byte token b'&\x19H\xc0r{\xa5\xd6\x0b\xf5\xb2\x1d\xc6\xf6]0'
Generate a secure hexadecimal token dd772eb0c11c4995c3c9db5a20a555c31d70547c30df31e818be7c7832bb44f1
Generate a secure URL https://pynative.com/customer/eric/reset=GzWfp5xCcuFsnEUb9qqN_v94_XOx9hPwSGszdx4rNBk
tokens使用多少字节
为了抵御蛮力攻击和时序攻击,tokens需要具有足够的随机性。根据专家的说法,32字节(256位)的随机性足以抵御蛮力攻击。您应该根据您的要求选择字节大小。
使用secrets.compare_digest(a,b)减少时序攻击

为了降低时序攻击的风险,secrets模块具有compare_digest(a,b)功能。如果字符串a和b相等,则此函数返回True,否则返回False以降低计时攻击的风险。


secrets模块的练习示例
我们现在看看这个例子,此示例中,我们生成临时密码并在临时hard-to-guess URL上发送此密码,以便客户端可以使用此URL重置其密码。
生成一个十个字符的字母数字密码,至少包含一个小写字符,至少一个大写字符,至少一个数字和一个特殊字符
生成临时URL
示例:
import secrets
import string

stringSource  = string.ascii_letters + string.digits + string.punctuation
password = secrets.choice(string.ascii_lowercase)
password += secrets.choice(string.ascii_uppercase)
password += secrets.choice(string.digits)
password += secrets.choice(string.punctuation)
for i in range(6):
    password += secrets.choice(stringSource)
char_list = list(password)
secrets.SystemRandom().shuffle(char_list)
password = ''.join(char_list)
print ("Secure Password is ", password)
print ("Reset password URL Link")
SecureURL = "https://pynative.com/user/jhon/reset="
SecureURL+=secrets.token_urlsafe(32)
print(SecureURL)
输出:
Secure Password is  r6DS)nzc*-
Reset password URL Link
https://pynative.com/user/jhon/reset=BdXvTTm_GtVcVko0W4Qf8jyqj9gE5I8KkWOEerAkmrk

用户评论