Rails中的会话和Cookie是如何工作的?

12

我之前一直在使用 Devise 来处理 Rails 应用程序的身份验证,但是从未真正理解它的工作原理。因为 Devise 也使用了 Rails 上设置的会话存储配置,所以我认为这是一个关于使用 Rails 处理会话的问题。

基本上,我是一个身份验证新手。我阅读过一些关于身份验证的文章,但大多数都涉及到抽象的库(他们谈论引擎、中间件等),而对我来说并不太有意义。我真的想了解更低级别的细节。

以下是我目前了解的内容。

我知道关于 cookies 和 sessions。Cookies 是存储在客户端的字符串,用于在多个 HTTP 请求之间保持会话。

以下是我的基本身份验证理解(如果我理解有误,请纠正我):

  1. 用户登录时,我们向服务器发送 SSL 加密请求。如果凭据有效,我们将保存一个称为会话 ID 的随机字符串作为与用户 ID 相关联的有效会话 ID 在数据库(或任何其他数据存储)上。此会话 ID 在每次用户登录/注销时更改。

  2. 在将该会话 ID 保存到我们的数据存储后,我们返回一个响应,要求浏览器设置一个带有会话 ID 的 cookie。该会话 ID 以及用户 ID 将随后被发送到域名的连续请求中,直到到期为止。对于每个请求,我们的服务器将检查标头上的会话 ID,并验证该会话 ID 是否对该用户 ID 有效。如果是,则将其视为已通过身份验证的用户。

以下是我的问题:

  1. 我读到的内容称,从 Rails 2 开始,默认使用 CookieStore(而不是 SessionStore),它使用 SHA512 生成会话哈希值(而不是会话 ID),并且所有这些都存储在一个 cookie 中,这意味着多个用户 ID 可以使用相同的会话哈希值,而只需同样有效。对我来说,这似乎是一件非常危险的事情,因为它公开了大量使用单个密钥存储的哈希值,并且基于此密钥构建了整个身份验证系统。是否有真实世界的大型应用程序使用哈希而不是存储在服务器端的会话 ID?

  • 关于在服务器端存储活动会话ID的主题,我还看到过可以切换为使用不同种类的Rails会话存储的信息。基于此,我听说有些系统将身份验证系统移出作为服务并使用身份验证令牌。什么是身份验证令牌,它与会话ID有何不同?

  • 似乎我只需猜测一个随机字符串(用于哈希和服务器端会话)即可获取现有会话。有没有办法防止这种情况发生?使用更多存储在cookie中的值是否正常?(例如用户名、真实姓名或甚至另一个用于身份验证的哈希值)

  • 我知道我要求很多,但我相信这对像我一样不理解身份验证的人会很有用,并且对于了解这个主题打下坚实的基础。


    这是一个非常好的问题,Devise 的晦涩长期以来一直是我们公司采用它的障碍。我会密切关注这个问题。 - Drenmi
    生成的哈希值不仅由已登录用户的属性组成。也就是说,您无法生成重复的SHA1哈希值。 - ilan berci
    1个回答

    3
    我读到Rails 2默认使用CookieStore(而非SessionStore),生成带有SHA512的会话哈希(而不是会话ID),所有这些都存储在cookie中,这意味着多个用户ID可以实际上具有相同的会话哈希,并且它将正常工作。对我来说,这是一件非常危险的事情,使用单个密钥存储在服务器上的大量哈希,并基于此密钥构建整个身份验证系统。

    是的,乍一看似乎很可怕,但我不确定真正的危险在哪里。在Rails 4中,会话数据使用PBKBF2加密,然后使用您的会话密钥进行签名。这种签名有助于检测加密会话内容是否被篡改,如果检测到篡改,服务器将拒绝该会话。

    https://cowbell-labs.com/2013-04-10-decrypt-rails-4-session.html

    如果有人获得了会话令牌(用于签署会话cookie),那么您可能面临比最终用户试图模拟错误用户更大的问题。

    是否有一个真实世界的大型应用程序使用哈希而不是存储服务器端会话ID?

    我老实说不知道这个问题的答案,但我认为Rails的“默认”意味着有更多的网站使用cookie会话存储。

    关于在服务器端存储活动会话ID的主题,我还读到过可以切换到使用不同类型的会话存储的Rails。基于此,我听说系统将身份验证系统作为服务移出并改用auth令牌。什么是auth令牌,它与会话ID有何不同?

    我现在正在服务器上进行此操作 - 用户认证时会生成一个随机哈希值,该哈希值被存储、加密和签名在cookie中。Cookie哈希是服务器端数据存储的关键(在我的情况下是Redis,但可以是关系数据库或memcache或任何你喜欢的东西),实际会话数据是与该键映射的存储在服务器端。这样,客户端手上的会话数据就少了一些,人们有可能解密和分析它,因此通常会更安全。
    似乎我只需猜测一个随机字符串(用于哈希和服务器端会话)即可抓取现有会话。有没有方法防止这种情况发生?使用更多存储在cookie中的值是否正常?(例如用户名、真实姓名甚至是另一个用于身份验证的哈希值)。
    是的,你可以这样做,但需要很长很长时间。你还需要猜测如何签署新篡改的cookie数据,以使其与服务器期望在其侧看到的内容匹配,并且使用了相当大的密钥进行签名。

    我认为保持身份验证状态没有比使用cookie更好的选择(如果您感觉奇特并且不太关心遗留浏览器的支持,那么HTML5本地存储也可以使用)。


    啊..这很有道理,我忘记了它实际上加密了哈希值,这使得它更加困难。我仍然有点困惑于基于令牌的身份验证与会话 ID。根据您的解释,我猜您是指基于令牌的身份验证?那么基于令牌的身份验证和仅使用存储在某个地方的会话 ID(它也映射到会话信息,对吧?)之间有什么区别呢? - gerky
    我所说的“会话令牌”是用于签署会话的服务器端“密钥”。对于身份验证,通常会在会话本身中存储某种用户ID,该ID可以是签名的cookie,也可以是使用存储在cookie中的会话密钥的服务器端。 - Mike Desjardins

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接