81

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

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

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

4

3 回答 3

195

token_authenticatable容易受到定时攻击,这在这篇博文中有很好的解释。这些攻击是token_authenticatable从 Devise 3.1 中删除的原因。有关详细信息,请参阅plataformatec 博客文章

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

  1. 必须通过 HTTPS 发送。

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

  3. 必须安全地进行比较。

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

  5. 根据某种逻辑应该过期。

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

扩展和解释我的答案:

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

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

    • 为了安全地传输用户的凭据(用户名/电子邮件/密码),您将不得不使用摘要式身份验证,但现在这并没有削减它,因为加盐哈希可以被蛮力强制

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

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

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

    为了解释为什么这是必要的,我建议阅读sysrandom的自述文件和博客文章如何在各种编程语言中生成安全随机数

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

    不要使用 Rails finder查找用户记录,例如User.find_by(auth_token: params[:auth_token]). 这很容易受到定时攻击!

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

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

    • 为每个用户存储尽可能多的加密令牌,以允许当前会话。因此,如果您想在 2 个不同的设备上允许 2 个会话,请在数据库中保留 2 个不同的令牌哈希。此选项实施起来不太简单,但绝对更安全。它还有一个好处是允许您为您的用户提供选项,通过撤销他们的令牌来结束特定设备中的当前活动会话(就像GitHub和 Facebook 一样)。

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

    如果 6 个月未使用令牌,Google 就会过期

    如果两个月没有使用,Facebook 就会过期令牌

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

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

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

为了让您开始,您可以查看这个要点(由 Devise 的一位作者提供),了解如何使用 Devise 实现令牌身份验证。最后,关于保护 API 的 Railscast应该会有所帮助。

于 2013-09-09T09:27:51.310 回答
11

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

于 2015-04-19T18:14:32.057 回答
3

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

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

最后你应该通过这些加密和解密“无法解密存储的加密数据”来获得更多的安全性。

于 2013-09-11T13:06:21.627 回答