【问题标题】:Unique session id in pythonpython中的唯一会话ID
【发布时间】:2010-10-23 12:06:46
【问题描述】:

如何在 Python 中生成唯一的会话 ID?

【问题讨论】:

标签: python session


【解决方案1】:

Python 3.6 使这里的大多数其他答案都有些过时了。包括 3.6 及更高版本在内的版本包括 secrets 模块,该模块正是为此目的而设计的。

如果您需要为网络上的任何目的生成加密安全字符串,请参阅该模块。

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'

【讨论】:

  • 我还应该在这个令牌上附加一个 HMAC 吗?防止人们劫持会话?
【解决方案2】:

更新:2016-12-21

在过去的 5 年里发生了很多事情。 /dev/urandom 已更新,现在被认为是现代 Linux 内核和发行版上的高熵随机源。在过去的 6mo 中,我们看到了使用 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 的“How to Crack a Linear Congruential Generator”或NIST's resources on Random Number Generation。如果您仍想使用 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 atm 中最好的 OpenSSL API,因为维护 pyOpenSSL 似乎只是为了支持旧版应用程序。

【讨论】:

  • 那些关于 UUID 问题的引用很有帮助。感谢您发布。问题:您认为生成会话 ID 的最佳方式是什么?特别是对于您在 UUID 实现中引用的错误,您将如何以不同的方式进行处理?我现在正在写这样的东西,并试图提出最好的方法。它还必须是容错的——例如,不能依赖于与数据库服务器的连接。
  • 如果我们去掉所有的绒毛,你基本上说的是 OpenSSL.rand.bytes(16) 是安全的,但 os.urandom(16) 不是。根据文档,os.urandom 的目的是“返回适合加密使用的 n 个随机字节的字符串”。如果生成一个好的会话 ID 不是 os.urandom 适合的“加密用途”,那么它意味着什么?也许正确的解决方案对您来说太简单了,但这就是您的 Python。毫无意义的绒毛不会让事情更安全。
  • @SeunOsewa,您对文档的看法是正确的,os.urandom 旨在适合加密使用,但不幸的是,情况并非总是如此。 FreeBSD 和 OS-X 为 urandom 提供了一个很好的资源池,Linux 时好时坏(尽管越来越好)。显式总比隐式好。顺便说一句,我发布此内容的原因是因为我在未检查会话 ID 冲突并且用户看到彼此信息的真实世界情况下遇到了会话 ID 冲突。原因? urandom 没有正确播种。 :-/ 现实有时会咬人。
  • @SeunOsewa 你说得对,OpenSSL 和 os.urandom 都使用相同的熵源 (/dev/urandom) 并且具有相同的安全级别。
  • 暂定-1。您在没有证据的情况下声称 os.urandom 的随机性不足以保证安全,而 OpenSSL(例如通过 M2Crypto)更好。同时@ramirami 声称(也没有证据)实际上两者都使用相同的潜在熵源。我不知道谁是对的,但无论如何我都投反对票;我不喜欢 FUD 和这里的大胆声明(os.urandom 使用或可能在某些平台上使用比 OpenSSL 更糟糕的熵源,以至于前者在后者安全的情况下被密码破解)需要证实有用。
【解决方案3】:
import os, base64
def generate_session():
    return base64.b64encode(os.urandom(16))

【讨论】:

  • 我不知道,但这似乎是一个有效的解决方案。但是,我建议您去掉尾随的“==”,并包含一个时间戳,以减少碰撞的可能性。
  • 40 亿次迭代后发生碰撞的几率是 80 亿分之一。如果我想进一步减少碰撞的机会,我可以增加位数,即 os.urandom(32)。而且我不明白剥离尾随“==”应该达到什么目的。
  • 可以删除尾随的 == 以节省空间。解码它所要做的就是将其填充回 4 的最高倍数。使用 urandom,可以获得非常低的熵并最终得到重复。使用时间戳更好。
  • 真的吗? (我看不出一个 4 字节的时间戳比额外的 4 个字节的随机性更好,但是)如果你所说的低熵是真的,那么我会选择一个自动递增的 session_id,因为它可以用于许多会话请求大致同时发出。即使在低熵情况下,除了 urandom 之外,我也不会返回重复的 32 字节字符串。伪随机算法可能是可攻击的,但它们不会返回重复的 32 字节序列。
  • 我认为这是满足我需求的最佳解决方案。我尝试了 M2Crypto 和 PyCrypto,但在 Windows 上安装和运行都存在严重问题。
【解决方案4】:

它可以像创建一个随机数一样简单。当然,您必须将会话 ID 存储在数据库或其他东西中,并检查您生成的每个 ID 以确保它不是重复的,但如果数字足够大,很有可能永远不会。

【讨论】:

【解决方案5】:

您可以像这样使用uuid library

导入 uuid my_id = uuid.uuid1() # 或 uuid.uuid4()

【讨论】:

  • 这就是我要找的东西!
  • @Gumbo: uuid 会使用你电脑的mac地址和正常运行时间之类的东西来产生一个随机的uuid,为什么不是随机的?
  • uuid1()、uuid4() 甚至 uuid5() 都不是好的会话。有关安全会话 ID 示例,请参阅 stackoverflow.com/questions/817882/unique-session-id-in-python/…
  • Wiki 说Version 4 UUIDs use a scheme relying only on random numbers.,它对会话令牌有什么不好? uuid5 和 uuid1 不是基于随机数的,那为什么 uuid4 不好呢?
  • UUID 不使用加密安全随机数生成器,因此不适合生成安全会话 ID。 Python 3.6+ 的正确答案是:stackoverflow.com/a/55661405
猜你喜欢
  • 2015-01-12
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 2012-09-21
  • 2011-07-29
相关资源
最近更新 更多