python 为 cookie 生成随机会话 ID 的最安全方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2541742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-04 00:53:33  来源:igfitidea点击:

Most secure way to generate a random session ID for a cookie?

pythoncookiessessionsecurity

提问by ensnare

I'm writing my own sessions controller that issues a unique id to a user once logged in, and then verifies and authenticates that unique id at every page load. What is the most secure way to generate such an id? Should the unique id be completely random? Is there any downside to including the user id as part of the unique id?

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

采纳答案by keturn

If the only information in the cookie is an identifier, essentially a label, the only attack you're trying to protect from is an attacker guessing what it is. So use some random bytes. Enough random bytes that it's "unguessable."

如果 cookie 中的唯一信息是标识符,本质上是一个标签,那么您试图防止的唯一攻击就是攻击者猜测它是什么。所以使用一些随机字节。足够多的随机字节使其“无法猜测”。

Then squish the random bytes into something that fits within the confines of which characters you can use in a HTTP cookie. base64 works for this. It's not absolutely optimal, because there are more than 64 cookie-safe characters and it tends to leave trailing ==characters which add bytes to the header but not randomness, but that's fine. It works and Python can probably do the base64 encoding faster than anything else we can come up with.

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

If you also want to prepend the user ID to it, that will make things easier to trace and debug, which will probably make your life easier, so go ahead. It doesn't give an attacker any significant advantage. (unless they manage to steal one without being able to otherwise determine what user they're stealing from, which seems unlikely.)

如果您还想在其前面添加用户 ID,这将使跟踪和调试变得更容易,这可能会使您的生活更轻松,所以继续。它不会给攻击者任何显着的优势。(除非他们设法窃取了一个而无法确定他们从哪个用户那里窃取,这似乎不太可能。)

回答by retracile

Go buy Bruce Schneier's Secrets and Liesand his Practical Cryptography. Go ahead and order Ross Anderson's Security Engineering 2nd Ed.while you're at it. Now, read Secrets and Lies -- trust me, it's a fun read. :) Then read Practical Cryptography. At that point you should have a better grounding in what you need to do when implementing software that needs some security. Go ahead and do your rough-draft implementation. Now that your copy of Security Engineering has arrived, read it... though that one you may want to digest a bit slower; it's a rather heavy tome.

去购买 Bruce Schneier 的Secrets and Lies和他的Practical Cryptography。继续订购罗斯安德森的安全工程第 2 版。当你在做的时候。现在,阅读《秘密与谎言》——相信我,这是一本有趣的书。:) 然后阅读实用密码学。那时,您应该对在实施需要一定安全性的软件时需要做的事情有更好的了解。继续做你的草稿实施。既然您的安全工程副本已经到货,请阅读它……尽管您可能希望消化得慢一点;这是一本相当沉重的书。

There is also a whitepaper on web authentication dos and don'tsthat is worth reading and a bit more directly applicable to what you're doing. I still recommend the books above.

还有一份关于 Web 身份验证注意事项白皮书,值得一读,并且更直接适用于您正在做的事情。我还是推荐上面的书。

And another timely article from LWN.netwhich lists a good number of pitfalls you need to work to avoid. (BTW, LWN.netis well worth subscribing to, and I highly recommend it. The above link allows free access to that article which otherwise would not be available to non-subscribers yet.)

以及来自 LWN.net 的另一篇及时文章,其中列出了您需要努力避免的大量陷阱。(顺便说一句,LWN.net非常值得订阅,我强烈推荐它。上面的链接允许免费访问该文章,否则非订阅者将无法访问该文章。)

回答by ensnare

Use the UUIDmodule in 2.5 and higher. This way they can't be guessed since they are not sequential. If you want them to be really secure you could salt them with the user's id and then SHA1 hash them, Base64encode the result and then use that as the value. That way you could verify on the server side that they really are your cookies and not just something that some spammer is generating and throwing at your server. And to make them even more secure make sure they only last for a set amount of time on the server as well as the client. Python 2.6.5 has an HMACimplemenation built in that you could use on the generated UUID as well.

在 2.5 及更高版本中使用UUID模块。这样就无法猜测它们,因为它们不是连续的。如果您希望它们真正安全,您可以使用用户的 id 对它们进行加盐,然后对它们进行 SHA1 散列,Base64对结果进行编码,然后将其用作值。这样您就可以在服务器端验证它们确实是您的 cookie,而不仅仅是某些垃圾邮件发送者正在生成并向您的服务器投掷的东西。为了使它们更加安全,请确保它们仅在服务器和客户端上持续一定的时间。Python 2.6.5 内置了HMAC实现,您也可以在生成的 UUID 上使用它。

回答by Thomas Leonard

You can use os.urandom:

您可以使用os.urandom

os.urandom(n)

Return a string of n random bytes suitable for cryptographic use.

This function returns random bytes from an OS-specific randomness source. The returned data should be unpredictable enough for cryptographic applications, though its exact quality depends on the OS implementation. On a UNIX-like system this will query /dev/urandom, and on Windows it will use CryptGenRandom. If a randomness source is not found, NotImplementedError will be raised.

New in version 2.4.

os.urandom(n)

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

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

2.4 版中的新功能。

回答by Sébastien Deprez

If you're using Python 3.6+, you can use the new library secrets.

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

from secrets import token_urlsafe

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

回答by Buktop

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

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

"Warning: The pseudo-random generators of this [random] module should not be used for security purposes. Use os.urandom() or SystemRandom if you require a cryptographically secure pseudo-random number generator."

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

"os.urandom function returns random bytes from an OS-specific randomness source. The returned data should be unpredictable enough for cryptographic applications, though its exact quality depends on the OS implementation. On a UNIX-like system this will query /dev/urandom, and on Windows it will use CryptGenRandom(). If a randomness source is not found, NotImplementedError will be raised.

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

For an easy-to-use interface to the random number generator provided by your platform, please see random.SystemRandom."

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

回答by WhyNotHugo

I would avoid the random factor completely. What I've generally done is:

我会完全避免随机因素。我一般做的是:

  • Generate a sequential session_id(which I store locally).
  • When the user logs in, sign session_idwith a private key (I use itsdangerousfor this).
  • When I get a request, if the session_id's signature is intact, I proceed, otherwise, 403 (400 would make sense too).
  • 生成一个序列session_id(我存储在本地)。
  • 当用户登录时,session_id使用私钥进行登录(我itsdangerous为此使用)。
  • 当我收到请求时,如果session_id's 签名完好无损,我继续,否则, 403 (400 也有意义)。

Note that I store the session_idlocally because I want to be able to expire end sessions prematurely.

请注意,我将其存储在session_id本地,因为我希望能够提前结束结束会话。

If your sessions always last a fixed amount of time, and you don't need to end them prematurely, you can simply sign user_id + datetime.now(). This allows completely stateless session management.

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

回答by Andrew Hare

The best way would be to generate a UUID, using the uuid.uuid1function:

最好的方法是使用以下函数生成 UUIDuuid.uuid1

Generate a UUID from a host ID, sequence number, and the current time.

根据主机 ID、序列号和当前时间生成 UUID。