我正在使用Rails API建立一个简单的api,并希望确保我在这里正确的轨道。我正在使用设计来处理登录,并决定使用Devise的token_authenticatable
选项,该选项生成一个API密钥,您需要随每个请求一起发送。
我将API与骨干/牵线木偶前端配对,我一般想知道如何处理会话。我的第一个想法是将api密钥存储在本地存储或cookie中,并在页面加载时检索它,但是从安全的角度来看存储api密钥的方式让我感到困扰。通过查看本地存储/ cookie或嗅探任何经过的请求来获取api密钥并不容易,并使用它来无限期地冒充该用户?我目前正在每次登录时重置api密钥,但即使这样也很频繁 - 任何时候你登录任何设备,这意味着你会被其他人登录,这是一种痛苦。如果我可以放弃这种重置,我觉得从可用性的角度来看它会有所改善。
我在这里可能完全错了(并且希望我是),任何人都可以解释这种方式的认证是否可靠安全,如果不是,那么一个好的替代方案是什么?总的来说,我正在寻找一种方法,我可以安全地让用户“登录”访问API,而无需经常强制重新验证。
答案 0 :(得分:182)
token_authenticatable
容易受到时间攻击的影响,this blog post对此进行了详细解释。这些攻击是token_authenticatable
从Devise 3.1中删除的原因。有关详细信息,请参阅plataformatec blog post。
要拥有最安全的令牌认证机制,令牌:
必须通过HTTPS发送。
加密强度必须是随机的。
必须进行安全比较。
不得直接存储在数据库中。只有令牌的哈希值才能存储在那里。 (记住,令牌=密码。我们不在db中以明文形式存储密码,对吗?)
应该按照某种逻辑过期。
如果你放弃其中一些支持可用性的观点,你最终会得到一种不那么安全的机制。就这么简单。如果您满足前三个要求并限制对数据库的访问,那么您应该足够安全。
扩展并解释我的回答:
使用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就应该是安全的。
使用以下代码生成令牌:
SecureRandom.hex
只有在使用Ruby 2.5 +时才会这样。sysrandom
,如果您使用较旧的Ruby。有关为何需要这样做的说明,我建议您阅读sysrandom
的自述文件和博文How to Generate Secure Random Numbers in Various Programming Languages。
使用用户的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查找程序查找用户记录。这很容易受到时间攻击的影响!
如果您要为每个用户同时拥有多个应用程序/会话,那么您有两个选择:
将未加密的令牌存储在数据库中,以便可以在设备之间共享。这是一种不好的做法,但我想你可以用UX的名义来做(如果你信任你的员工有DB访问权限)。
为每个用户存储尽可能多的加密令牌,以允许当前会话。因此,如果要在2个不同的设备上允许2个会话,请在数据库中保留2个不同的令牌哈希值。这个选项实现起来不那么简单,但它肯定更安全。它还具有以下优势:允许您通过撤销其令牌为用户提供结束特定设备中当前活动会话的选项(就像GitHub和Facebook一样)。
应该有某种机制导致令牌过期。实施此机制时,要考虑用户体验与安全性之间的权衡。
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后过期 几天,这个人将不得不再次通过登录流程 得到一个新的令牌。
升级到Rails 4以使用其加密的cookie存储区。如果不能,则自行加密cookie商店,如建议的here。将身份验证令牌存储在加密的Cookie存储中绝对没有问题。
您还应该有一个应急计划,例如,rake任务可以重置令牌的子集或数据库中的每个令牌。
为了帮助您入门,您可以查看this gist(由Devise的作者之一)了解如何使用Devise实现令牌身份验证。最后,the Railscast on securing an API应该会有所帮助。
答案 1 :(得分:9)
根据该项目的自述文件,devise_token_auth gem受到此StackOverflow帖子的启发:https://github.com/lynndylanhurley/devise_token_auth
答案 2 :(得分:3)
您可以尝试在您的API中使用 rails4 ,它提供更高的安全性并使用设计3.1.0rc
在Rails 4.0中,已经将几个特征提取到了宝石中。
Devise 3.1.0.rc在Rails 3.2和Rails 4.0上运行。 http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/
Devise是3.1.0rc中TokenAuthenticatable
的弃用,但是您可以为安全问题构建自己的 TokenAuthenticatable
方法。它更可靠,更安全。
对于令牌,会话商店,您可以浏览http://ruby.railstutorial.org/chapters/sign-in-sign-out和http://blog.bigbinary.com/2013/03/19/cookies-on-rails.html以获得更明确的信息。
最后,您应该通过这些加密和解密“Unable to decrypt stored encrypted data”来获得更高的安全性。