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

我正在将API与主干/ puppeteer 前端配对,我通常想知道应该如何处理会话.我的第一个 idea 是将api密钥存储在本地存储器或cookie中,然后在页面加载时检索它,但从安全Angular 来看,关于以这种方式存储api密钥的一些问题困扰着我.通过查看本地存储/cookie或嗅探任何通过的请求,并使用它无限期地模拟该用户,获取api密钥不是一件容易的事吗?目前,我正在每次登录时重置api密钥,但即便如此,这似乎也很频繁——无论你何时登录任何设备,这意味着你都会在其他设备上注销,这是一种痛苦.如果我能放弃这个重置,我觉得从可用性的Angular 来看,它会有所改进.

我在这里可能完全错了(希望我错了),有人能解释一下这种身份验证方式是否可靠安全,如果没有,那么什么是好的替代方案吗?总的来说,我正在寻找一种方法,可以安全地让用户"登录"到API访问,而不必频繁地强制重新验证.

推荐答案

token_authenticatable容易受到定时攻击,这在this blog post中得到了很好的解释.这些攻击是token_authenticatable从Desive 3.1中删除的原因.更多信息请参见plataformatec blog post.

要拥有最安全的令牌身份验证机制,令牌:

  1. 必须通过HTTPS发送.

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

  3. 必须进行可靠的比较.

  4. 不能直接存储在数据库中.只有令牌的散列可以存储在那里.(记住,token=password.我们不会在数据库中以明文形式存储密码,对吗?)

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

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

扩展并解释我的答案:

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

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

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

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

  3. 使用用户ID、邮箱或其他属性查找用户记录.然后,将该用户的令牌与Devise.secure_compare(user.auth_token, params[:auth_token]的请求令牌进行比较.

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

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

    • 将未加密的令牌存储在数据库中,以便在设备之间共享.这是一种不好的做法,但我想你可以以用户体验的名义(如果你相信你的员工有数据库访问权限的话)来做这件事.

    • 每个用户存储尽可能多的加密令牌,以允许当前会话.因此,如果希望在两个不同的设备上允许两个会话,请在数据库中保留两个不同的令牌哈希.这个选项实现起来不那么简单,但肯定更安全.它还有一个好处,那就是你可以通过撤销用户的 token (就像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的本地移动应用将获得长期访问权限

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

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

为了让您开始学习,您可以查阅this gist篇(Desive的作者之一)关于如何使用Desive实现令牌身份验证的文章.最后,the Railscast on securing an API应该是有帮助的.

Ruby-on-rails相关问答推荐

使用turbo流的部分渲染在rails 7中不起作用.

在Rails中,如何将帮助器方法添加到属性/列?

使用带有 Paper Trail gem 的子类

在 POST 请求中添加了 Rails 奇怪的参数

这种使用on:的语法在 Ruby on Rails 中意味着什么?

Rspec期望()与期望{}

将日期时间转换为月、日和年?

rails select标签,预先 Select 了多个值

如何获取 Ruby on Rails 生成的表单元素 id 以供 JavaScript 参考?

使用 Ruby on Rails 从原始 IP 地址获取用户国家名称

FactoryGirl + Faker - 为数据库种子数据中的每个对象生成相同的数据

如何验证 ActiveRecord 中邮箱字段的格式?

如何在 Ruby 中创建一个新的 Date 实例

Rails:使用 gem 卸载特定版本的库

遇到在早期版本的 Rails 中使用 attr_accessible 的情况时,Rails 4 中的禁止属性错误

按周/月/等和 ActiveRecord 分组?

Rails:一次添加多个 flash[:notice] 的简单方法

在 Rails 中命名布尔列

将数组传递到 hidden_​​field ROR

如何删除特殊字符?