【问题标题】:Is devise's token_authenticatable secure?devise 的 token_authenticable 安全吗?
【发布时间】:2013-09-07 10:56:47
【问题描述】:

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

我正在将 API 与骨干/牵线木偶前端配对,并且通常想知道我应该如何处理会话。我的第一个想法是将 api 密钥存储在本地存储或 cookie 中,并在页面加载时检索它,但从安全角度来看,以这种方式存储 api 密钥的一些事情让我感到困扰。通过查看本地存储/cookie 或嗅探任何通过的请求并使用它来无限期地冒充该用户来获取 api 密钥是不是很容易?我目前正在重置每次登录的 api 密钥,但即使这似乎很频繁 - 任何时候您在任何设备上登录,这意味着您将在其他所有设备上注销,这有点痛苦。如果我可以取消此重置,我觉得从可用性的角度来看它会有所改善。

我在这里可能完全错了(希望我错了),谁能解释这种方式的身份验证是否可靠安全,如果不是,还有什么好的选择?总的来说,我正在寻找一种方法,可以安全地让用户“登录”到 API 访问,而无需频繁强制重新验证。

【问题讨论】:

    标签: ruby-on-rails api authentication devise rails-api


    【解决方案1】:

    token_authenticatable 容易受到定时攻击,this blog post 对此进行了很好的解释。这些攻击是 token_authenticatable 从 Devise 3.1 中删除的原因。请参阅plataformatec blog post 了解更多信息。

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

    1. 必须通过 HTTPS 发送。

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

    3. 必须进行安全比较。

    4. 不得直接存储在数据库中。那里只能存储令牌的哈希值。 (记住,token = 密码。我们不会在数据库中以纯文本形式存储密码,对吧?)

    5. 按照某种逻辑应该会过期。

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

    扩展和解释我的答案:

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

      如果您不使用 HTTPS,那么可能会出现很多问题。例如:

      • 为了安全地传输用户的凭据(用户名/电子邮件/密码),您必须使用摘要式身份验证,但 that just doesn't cut it these days since salted hashes can be brute forced

      • 在 Rails 3 中,cookie 仅被 Base64 编码所覆盖,因此可以很容易地显示出来。请参阅Decoding Rails Session Cookies 了解更多信息。

        尽管如此,自 Rails 4 起,cookie 存储已加密,因此数据既经过数字验证,攻击者也无法读取。只要您的secret_key_base 不泄露,Cookie 就应该是安全的。

    2. 使用以下方式生成您的令牌:

      为了解释为什么这是必要的,我建议阅读sysrandom的自述文件和博客文章How to Generate Secure Random Numbers in Various Programming Languages

    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. 应该有某种机制导致令牌过期。在实施此机制时,请考虑用户体验和安全性之间的权衡。

      Google expires a token if it has not been used for six months.

      Facebook expires a token if it has not been used for two months:

      使用 Facebook SDK 的原生移动应用将获得长期访问权限 代币,有效期约为 60 天。这些令牌将被刷新一次 每天,当使用您的应用的人向 Facebook 的 服务器。如果没有请求,令牌将在大约 60 后过期 天,此人将不得不再次通过登录流程 获取新令牌。

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

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

    首先,您可以查看this gist(Devise 的作者之一)了解如何使用 Devise 实现令牌身份验证。最后,the Railscast on securing an API 应该会有所帮助。

    【讨论】:

    • 太棒了,这很有帮助 - 谢谢!这几乎肯定会得到正确的答案。如果您在处理 API 身份验证的最佳方式上添加您的意见/建议(特别是),赏金就是您的:)
    • 虽然这两种方法都会生成一个随机字符串,但 urlsafe_base64 会生成一个 url 安全字符串。这一切都在名义上。除非您想在 url (which you shouldn't) 中使用令牌,否则请使用 hex
    • 令牌!=密码。以纯文本形式存储令牌没有任何问题。以纯文本形式存储密码的问题在于密码可以在其他地方使用,而您的令牌不应该是这种情况。
    • @fatfrog No. Token == 密码。如果黑客或心怀不满的员工有权访问您的数据库,他应该无法以特定用户或管理员身份进行身份验证。
    • 我不同意,如果黑客或心怀不满的员工可以访问您的数据库,那么令牌是您最不需要担心的事情。他们已经掌握了您的数据。
    【解决方案2】:

    根据项目的自述文件,devise_token_auth gem 的灵感来自 StackOverflow 这篇文章:https://github.com/lynndylanhurley/devise_token_auth

    【讨论】:

      【解决方案3】:

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

      对于token、session store,你可以通过http://ruby.railstutorial.org/chapters/sign-in-sign-outhttp://blog.bigbinary.com/2013/03/19/cookies-on-rails.html获取更不稳定的。

      最后你应该通过这种加密和解密“Unable to decrypt stored encrypted data”来获得更高的安全性。

      【讨论】:

      • 有没有人有一个定制的替代品示例?
      猜你喜欢
      • 2020-03-22
      • 1970-01-01
      • 2014-01-11
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-03
      相关资源
      最近更新 更多