如何在Python中生成唯一的会话ID?
更新:2016-12-21
在过去的约5年里发生了很多事情。 /dev/urandom
已经更新,并且在现代Linux内核和发行版上被认为是高熵随机性源。在最近的6个月中,我们在使用Ubuntu的Linux 3.19内核上看到了熵饥饿问题,所以我认为这个问题并没有“解决”,但是从操作系统请求任意数量的随机数时很容易出现低熵随机性。
我不想这么说,但是这里发布的其他解决方案都与“安全会话ID”的正确性无关。
# pip install M2Crypto
import base64, M2Crypto
def generate_session_id(num_bytes = 16):
return base64.b64encode(M2Crypto.m2.rand_bytes(num_bytes))
uuid()
和os.urandom()
都不是生成会话ID的好选择。尽管两者都可以产生随机结果,但随机并不意味着它是安全的,因为熵不足。请参阅Haldir的"如何破解线性同余生成器"或NIST关于随机数生成的资源。如果您仍然希望使用UUID,则使用使用良好初始随机数生成的UUID:
import uuid, M2Crypto
uuid.UUID(bytes = M2Crypto.m2.rand_bytes(num_bytes)))
# UUID('5e85edc4-7078-d214-e773-f8caae16fe6c')
或者:# pip install pyOpenSSL
import uuid, OpenSSL
uuid.UUID(bytes = OpenSSL.rand.bytes(16))
# UUID('c9bf635f-b0cc-d278-a2c5-01eaae654461')
M2Crypto是目前Python中最好的OpenSSL API,因为pyOpenSSL似乎只维护以支持旧应用程序。
os.urandom
适用于加密用途的观点是正确的,但不幸的是,并非总是如此。FreeBSD和OS-X有一个很好的urandom池,Linux则好坏参半(虽然越来越好)。显式比隐式更好。顺便说一句,我发布这篇文章的原因是在现实世界情况下遇到了会话ID冲突,而没有检查会话ID冲突的用户可以看到彼此的信息。原因是urandom没有被适当地种子化。 :-/ 现实有时候令人沮丧。 - Seanos.urandom
不足以提供足够的随机性以保证安全性,但 OpenSSL(例如通过 M2Crypto)更好。与此同时,@ramirami 声称(同样没有证据)实际上两者使用相同的基础熵源。我不知道谁是对的,但我仍然会点踩;我不喜欢 FUD,这里的大胆声明(即 os.urandom
在某些平台上使用比 OpenSSL 更差的熵源,以至于在后者安全的情况下前者在密码学上已经被破解)需要提供证明才能有用。 - Mark AmeryPython 3.6及以上版本包括secrets
模块,专门为此目的设计,因此大多数其他答案已经有些过时了。如果您需要在Web上为任何目的生成加密安全的字符串,请参考该模块。
https://docs.python.org/3/library/secrets.html
示例:
import secrets
def make_token():
"""
Creates a cryptographically-secure, URL-safe string
"""
return secrets.token_urlsafe(16)
使用中:
>>> make_token()
'B31YOaQpb8Hxnxv1DXG6nA'
import uuid my_id = uuid.uuid1() # 或者 uuid.uuid4()
import os, base64
def generate_session():
return base64.b64encode(os.urandom(16))
可以简单地创建一个随机数。当然,你需要将会话 ID 存储在数据库中,并检查每个生成的 ID 是否重复,但如果数字足够大,那么很可能不会出现重复的情况。