为cookie生成随机会话ID的最安全方式?

时间:2010-03-29 22:42:53

标签: python cookies session security

我正在编写自己的会话控制器,在登录后向用户发出唯一ID,然后在每次加载页面时验证并验证该唯一ID。生成这样一个id最安全的方法是什么?唯一ID应该是完全随机的吗?将用户ID作为唯一ID的一部分包含在内是否有任何缺点?

8 个答案:

答案 0 :(得分:7)

去买Bruce Schneier的Secrets and Lies和他的Practical Cryptography。来吧,当你在它的时候订购Ross Anderson的Security Engineering 2nd Ed.。现在,阅读秘密和谎言 - 相信我,这是一个有趣的阅读。 :)然后阅读Practical Cryptography。此时,在实现需要一定安全性的软件时,您应该更好地了解需要做的事情。继续执行粗略草案实施。既然您的安全工程副本已经到了,请阅读它...虽然那个你可能想要消化得慢一点;这是一本相当沉重的书。

还有一个whitepaper on web authentication dos and don'ts值得一读,而且更直接适用于你正在做的事情。我仍然推荐上面的书。

another timely article from LWN.net列出了您需要努力避免的大量陷阱。 (BTW,LWN.net非常值得订阅,我强烈推荐它。上述链接允许免费访问该文章,否则非订阅者将无法使用该文章。)

答案 1 :(得分:4)

使用2.5及更高版本的UUID模块。这样他们就不会被猜到,因为它们不是连续的。如果你希望它们非常安全,你可以用用户的id加盐,然后SHA1哈希它们,Base64对结果进行编码,然后将其用作值。通过这种方式,您可以在服务器端验证它们确实是您的cookie,而不仅仅是某些垃圾邮件发送者正在生成并投入您服务器的内容。为了使它们更加安全,请确保它们仅在服务器和客户端上持续一段时间。 Python 2.6.5内置了HMAC实现,您可以在生成的UUID上使用它。

答案 2 :(得分:4)

如果cookie中的唯一信息是标识符,实际上是标签,那么您试图保护的唯一攻击是攻击者猜测它是什么。所以使用一些随机字节。足够的随机字节,它是“不可思议的。”

然后将随机字节挤压成适合您可以在HTTP cookie中使用的字符范围的内容。 base64适用于此。它并不是绝对最优的,因为有超过64个cookie安全字符,它往往会留下尾随==个字符,这些字符会在标题中添加字节而不是随机性,但这很好。它可以工作,Python可以比我们想出的任何其他东西更快地执行base64编码。

如果你还想为它添加用户ID,这将使跟踪和调试更容易,这可能会让你的生活更轻松,所以继续。它不会给攻击者任何重大优势。 (除非他们设法窃取一个而不能确定他们偷窃的用户,这似乎不太可能。)

答案 3 :(得分:4)

您可以使用os.urandom

  

os.urandom(n)的

     

返回一串适合加密使用的n个随机字节。

     

此函数返回来自OS特定随机源的随机字节。   对于加密应用程序,返回的数据应该是不可预测的,尽管它的确切质量取决于操作系统   实现。在类UNIX系统上,这将查询/ dev / urandom,   在Windows上,它将使用CryptGenRandom。如果是随机源   未找到,将引发NotImplementedError。

     

版本2.4中的新功能。

答案 4 :(得分:2)

如果您使用的是Python 3.6+,则可以使用新库secrets

from secrets import token_urlsafe

token = token_urlsafe(64)   # something like Drmhze6EPcv0fN_81Bj-nA....

答案 5 :(得分:0)

http://docs.python.org/2/library/random.html

“警告:此[随机]模块的伪随机生成器不应用于安全目的。如果需要加密安全的伪随机数生成器,请使用os.urandom()或SystemRandom。”

“os.urandom函数从特定于操作系统的随机源返回随机字节。返回的数据对于加密应用程序应该是不可预测的,尽管它的确切质量取决于操作系统实现。在类UNIX系统上,这将查询/ dev / urandom,在Windows上它将使用CryptGenRandom()。如果找不到随机源,将引发NotImplementedError。

有关平台提供的随机数生成器的易用界面,请参阅random.SystemRandom。“

答案 6 :(得分:0)

我会完全避免随机因素。我通常做的是:

  • 生成顺序session_id(我在本地存储)。
  • 当用户登录时,请使用私钥对session_id进行签名(我为此使用itsdangerous)。
  • 当我收到请求时,如果session_id的签名完好无损,我会继续,否则,403(400也会有意义)。

请注意,我在本地存储了session_id,因为我希望能够提前过期终止会话。

如果您的会话总是持续一段固定的时间,并且您不需要提前结束,则只需签署user_id + datetime.now()即可。这允许完全无状态的会话管理。

答案 7 :(得分:-2)

最好的方法是generate a UUID,使用uuid.uuid1函数:

  

从主机ID,序列号和当前时间生成UUID。