devise的token_authenticatable安全吗?


79

我正在使用Rails API构建一个简单的api ,并希望确保我在这里正确。我正在使用devise来处理登录,并决定使用Devise的token_authenticatable选项,该选项会生成一个API密钥,您需要随每个请求发送该API密钥。

我将API与主干/牵线木偶的前端配对,并且通常想知道应该如何处理会话。我的第一个想法是只将api密钥存储在本地存储或cookie中,并在页面加载时检索它,但是从安全角度来看,关于存储api密钥的某些事情困扰着我。通过查找本地存储/ cookie或嗅探通过的任何请求,并无限期地模拟该用户来获取api密钥,并非容易吗?我目前正在每次登录时重置api密钥,但即使这样看起来也很频繁-每当您在任何设备上登录时,这意味着您将在其他设备上都注销,这很痛苦。如果我可以放弃此重置,我认为从可用性的角度来看它将有所改善。

我在这里可能是完全错误的(并希望我是),任何人都可以解释这种方式进行身份验证是否可靠吗?总体而言,我正在寻找一种方法,可以安全地使用户“登录”到API访问权限,而无需经常强制进行重新身份验证。

Answers:


190

token_authenticatable很容易受到定时攻击,本博客文章对此进行了很好的解释。这些攻击是token_authenticatable从Devise 3.1中删除的原因。有关更多信息,请参见plataformatec博客文章

为了拥有最安全的令牌认证机制,令牌:

  1. 必须通过HTTPS发送。

  2. 必须是随机的,具有加密强度。

  3. 必须进行安全比较。

  4. 一定不能直接存储在数据库中。令牌的哈希只能存储在此处。(请记住,令牌=密码。我们不在明文数据库中存储密码,对吗?)

  5. 根据一些逻辑应该过期。

如果您放弃了其中的一些观点以支持可用性,那么您将最终获得一种不够安全的机制。就这么简单。如果满足前三个要求并限制对数据库的访问,则应该足够安全。

扩展并解释我的答案:

  1. 使用HTTPS。这绝对是最重要的一点,因为它处理嗅探器。

    如果您不使用HTTPS,那么很多事情都会出错。例如:

    • 为了安全地传输用户的凭证(用户名/电子邮件/密码),您必须使用摘要式身份验证,但是由于盐渍的哈希值可能被强行使用,因此这几天并没有减少它的使用

    • 在Rails 3中,仅通过Base64编码来覆盖cookie,因此可以很容易地发现它们。有关更多信息,请参见解码Rails会话Cookies

      但是从Rails 4开始,cookie存储被加密了,因此数据经过了数字验证,攻击者无法读取。只要您secret_key_base不被泄露,Cookie应该是安全的。

  2. 通过以下方式生成令牌:

    有关为什么这样做的必要说明,建议阅读sysrandom的README和博客文章如何用各种编程语言生成安全随机数

  3. 使用用户的ID,电子邮件或其他某些属性查找用户记录。然后,将该用户的令牌与请求的令牌进行比较Devise.secure_compare(user.auth_token, params[:auth_token]。如果您使用的是Rails 4.2.1+,则也可以使用ActiveSupport::SecurityUtils.secure_compare

    千万不能找到像一个Rails取景器的用户记录User.find_by(auth_token: params[:auth_token])。这很容易受到定时攻击!

  4. 如果每个用户将同时拥有多个应用程序/会话,则有两个选择:

    • 将未加密的令牌存储在数据库中,以便可以在设备之间共享。这是一种不好的做法,但是我想您可以以UX的名义(以及如果您信任数据库访问权限的员工)来做到这一点。

    • 要允许当前会话,为每个用户存储尽可能多的加密令牌。因此,如果要允许在2个不同的设备上进行2个会话,请在数据库中保留2个不同的令牌哈希。该选项实现起来不太直接,但绝对安全。它还具有允许您为用户提供通过撤销其令牌来终止特定设备中当前活动会话的选项(就像GitHub和Facebook一样)。

  5. 应该有某种机制可以使令牌过期。实施此机制时,请考虑UX和安全性之间的权衡。

    如果六个月未使用令牌,则Google会使令牌过期

    如果两个月内未使用令牌,Facebook将使令牌过期

    使用Facebook SDK的本机移动应用程序将获得寿命很长的访问令牌,有效期约为60天。当使用您的应用的人向Facebook的服务器发出请求时,这些令牌将每天刷新一次。如果未提出任何请求,则令牌将在约60天后过期,该人将不得不再次通过登录流程来获取新令牌。

  6. 升级到Rails 4以使用其加密的cookie存储。如果不能,那么加密自己cookie存储,如建议在这里。将身份验证令牌存储在加密的cookie存储中绝对没有问题。

您还应该有一个应急计划,例如,一个rake任务,以重置令牌的子集或数据库中的每个单个令牌。

为了让您入门,您可以(由Devise的一位作者检查)这个要点,以了解如何使用Devise实现令牌认证。最后,有关保护API的Railscast应该会有所帮助。


太好了,对您有很大帮助-谢谢!这几乎肯定会得到正确的答案。如果您对处理API身份验证的最佳方法(特别是对此)有意见/建议(特别是),则可以得到赏金:)
Jeff Escalante 2013年

1
虽然这两种方法都会生成一个随机字符串,但会urlsafe_base64生成一个url安全的字符串。都是名字。除非您想在URL中使用令牌(不应该),否则请使用hex
Ashitaka 2013年

2
令牌!=密码。用纯文本存储令牌没有错。用纯文本存储密码的问题是密码可以在其他地方使用,而令牌不应该这样。
fatfrog

2
@fatfrog号令牌==密码。如果黑客或心怀不满的员工有权访问您的数据库,则他将不能以特定用户或管理员身份进行身份验证。
Ashitaka 2013年

1
我不同意,如果黑客或心怀不满的员工可以访问您的数据库,那么令牌是您需要担心的最后一件事。他们已经有了您的数据。
fatfrog


3

您可以尝试通过API使用rails4,它提供了更高的安全性,并使用了devise 3.1.0rc

对于令牌,会话存储,您可以访问http://ruby.railstutorial.org/chapters/sign-in-sign-outhttp://blog.bigbinary.com/2013/03/19/cookies-on-rails .html以获得更不稳定的信息。

最后,您应该经历这种加密和解密“无法解密存储的加密数据”以获得更多的安全性。


有人有定制的替代品示例吗?
丹尼尔·莫里斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.