如何在Python的Flask中正确安全地处理cookie和会话?

时间:2013-12-01 17:18:19

标签: python security session cookies flask

在应用程序中,我正在编写此刻我已经在用户浏览器中保存了一个存储了会话ID的cookie,并且该ID被用作对包含用户信息的数据库中存储的会话的引用,包括事实if用户已正确登录。

我想查看我的解决方案的安全性,我盯着看看如何在登录时设置cookie,在服务器端存储的会话中存储什么以及如何在注销时销毁该信息,因为截至目前我的用户多年来一直没有登录,这不是我的意图。

我遇到的问题是如何在Flask中正确处理整个用户登录/会话/注销问题 - 有些人正在谈论使用Flask的Response.delete_cookie()函数,其他人使用.set_cookie将其过期( )到期时间为零,其他人提到Flask的会话模块,其他的危险模块......

对于应该与Flask,代码示例等一起使用的模块,最安全,正确和正确的处理方法是什么?

2 个答案:

答案 0 :(得分:20)

背景

方法#1

处理会话的简单而安全的方法是执行以下操作:

  • 使用包含会话ID(随机数)的会话cookie。
  • 使用密钥对会话cookie进行签名(以防止篡改 - 这是itsdangerous所做的事情。)
  • 将实际会话数据存储在服务器端的数据库中(按ID索引,或使用NoSQL键/值存储)。
  • 当用户访问您的页面时,您将从数据库中读取数据。
  • 当用户注销时,您将从数据库中删除数据。

请注意,有一些缺点。

  • 您需要维护该数据库后端(更多维护)
  • 您需要为每个请求(性能较低)点击数据库

方法#2

另一种选择是将所有数据存储在cookie中,并对所述cookie进行签名(并可选择加密)。然而,这种方法也存在许多缺点:

  • 后端更容易(维护更少,性能更好)。
  • 您需要小心不要包含用户在会话中看不到的数据(除非您正在加密)。
  • 您可以在Cookie中保存的数据量有限。
  • 您不能使单个会话无效(!)。

代码

Flask实际上implements signed session cookies already,因此它实现了方法#2。

要从#2到#1,你所要做的就是:

  • 生成随机会话ID(您可以使用os.urandom + base64)。
  • 将会话数据保存在数据库后端,按会话ID索引(使用例如JSON序列化它,如果需要Python对象则使用Picke,但如果可以,请避免使用)。
  • 用户注销时从数据库后端删除会话。

确保您受到针对会话固定攻击的保护。为此,确保在用户登录时生成新的会话ID ,并且不要重复使用现有的会话ID。

另外,请确保在会话上实现过期(只需添加“最后看到的”时间戳)。

你最有可能get some inspiration from Django's implementation

答案 1 :(得分:2)

我建议你使用带有simplekv模块的Flask KVSession插件来保存会话信息。

从概念上讲,Flask KVSession使用Flask会话接口为上述方法#1提供了一个实现。这样您就不必更改代码以使其运行,并且您可以使用扩展方法执行其他操作,例如会话到期。它还负责会话签名,并进行一些基本检查以防止篡改。您仍然希望通过HTTPS执行此操作,以绝对防止会话窃取。

Simplekv是处理各种数据存储格式的写入和读取的实际模块。这可以像平面文件一样简单,与Redis一样快,也可以像数据库一样持久(NoSQL或其他)。这是一个单独的模块的原因是Flask KVSession可以只是Flask的普通适配器,而无需了解存储机制。

您可以在http://flask-kvsession.readthedocs.org/en/latest/找到代码示例。如果您需要更多示例,我可以提供一个。

或者,如果您需要为Flask提供更多企业级和重量级服务器端实现,您还可以使用Beaker查看此配方,该工具用作WSGI中间件(意味着其他框架也使用它)。 http://flask.pocoo.org/snippets/61/。 Beaker API位于http://beaker.readthedocs.org/en/latest/

Beaker在Flask上提供的一个优势KVSession是Beaker会延迟加载会话,所以如果你不读取会话信息,它就不会在每次调用时建立与数据库的连接。但是,Beaker依赖于SQLAlchemy,它将是一个比simplekv模块更大的模块。

除非特定的性能案例很重要,否则我仍然会使用Flask KVSession,因为它的API更简单,代码库更小。