设计的token_authenticatable安全吗?

问题描述 投票:73回答:3

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

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

我可能在这里完全错了(并且希望我是),任何人都可以解释这种方式的认证是否可靠安全,如果不是,那么一个好的替代方案是什么?总的来说,我正在寻找一种方法,我可以安全地保持用户'登录'到API访问,而不经常强制重新认证。

ruby-on-rails api authentication devise rails-api
3个回答
181
投票

token_authenticatable易受时间攻击的影响,这在this blog post中得到了很好的解释。这些攻击是token_authenticatable从Devise 3.1中删除的原因。有关更多信息,请参阅plataformatec blog post

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

  1. 必须通过HTTPS发送。
  2. 密码强度必须是随机的。
  3. 必须安全地进行比较。
  4. 不得直接存储在数据库中。只有令牌的哈希值才能存储在那里。 (记住,令牌=密码。我们不在db中以明文形式存储密码,对吧?)
  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没有泄露,Cookies应该是安全的。
  2. 使用以下内容生成令牌: SecureRandom.hex只有你在Ruby 2.5+上。 宝石sysrandom如果你是一个旧的Ruby。 为了解释为什么这是必要的,我建议阅读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。 使用像User.find_by(auth_token: params[:auth_token])这样的Rails查找程序找不到用户记录。这很容易受到定时攻击!
  4. 如果您要为每个用户同时拥有多个应用程序/会话,那么您有两个选择: 将未加密的令牌存储在数据库中,以便可以在设备之间共享。这是一种不好的做法,但我想你可以用UX的名义来做(如果你信任你的员工有DB访问权限)。 为每个用户存储尽可能多的加密令牌,以允许当前会话。因此,如果要在2个不同的设备上允许2个会话,请在数据库中保留2个不同的令牌哈希值。这个选项实现起来不那么简单,但它肯定更安全。它还有一个好处,允许您通过撤销其令牌为用户提供结束特定设备中当前活动会话的选项(就像GitHub和Facebook一样)。
  5. 应该有某种机制导致令牌过期。实施此机制时,要考虑用户体验和安全性之间的权衡。 Google expires a token if it has not been used for six monthsFacebook 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应该会有所帮助。


9
投票

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


3
投票

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

对于令牌,会话存储,您可以通过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”来获得更多的安全性。

© www.soinside.com 2019 - 2024. All rights reserved.