【问题标题】:can't verify CSRF token authenticity after session expires - Rails + devise + redis会话过期后无法验证 CSRF 令牌的真实性 - Rails + devise + redis
【发布时间】:2017-07-15 15:46:37
【问题描述】:

我们在将会话移动到 Redis 时启动的 CSRF 令牌存在问题。问题是用户退出并离开登录屏幕很长时间,例如过夜。然后,在早上,第一次登录尝试总是失败,因为表单 CSRF 令牌不再有效,因为 redis 会话已从服务器中删除(TTL)。

我在网上搜索了几个小时,但不知道什么是正确的方法。添加这个文件解决了这个问题:

class SessionsController < Devise::SessionsController
  skip_before_filter :require_no_authentication, only: [:new]
end

但从我read online 看来,这是一个安全风险。我一直在寻找,但几乎没有其他选择:

  • 尝试失败时,从服务器返回一个新令牌并重新提交表单
  • 在提交表单之前,进行 ajax GET 调用以检索新令牌
  • 将令牌添加到登录控制器上的请求标头中

如果我正确理解了安全风险,我看不出这些解决方案如何解决安全问题。我的意思是,从我读到的未受保护的登录 API 的风险是,攻击者可以欺骗其他人登录到攻击者的个人资料并输入私人数据,然后攻击者可以使用这些数据。因此,使用这些解决方案中的任何一个,攻击者都可以模仿相同的行为并自行入侵,对吗?

解决此问题最安全的方法是什么?

【问题讨论】:

    标签: ruby-on-rails security devise csrf


    【解决方案1】:

    我通过添加一个 API 来获取新令牌并在登录表单长时间打开时使用它来修复它。代码:

    app/controllers/my_controller.rb:

    def token
      render json: { token: form_authenticity_token }, status: :ok
    end
    

    signin.html:

    $('form#login').submit(function(e) {
        var that = this;
        e.preventDefault();
        // assuming the session TTL is 30 min
        if (new Date() - window.loginPageRenderedAt > 1800000) {
          $.get('token', function(data) {
            var token = data.token;
            $('input[name=authenticity_token]').val(token)
            that.submit();
          }).fail(function() {
            that.submit();
          })
        } else {
          this.submit();
        }
    }
    

    【讨论】:

      【解决方案2】:

      所选答案会增加潜在的安全风险。考虑用户在登录页面上输入他们的凭据并将其保持打开状态的情况 - 我认为这是被规避的令牌的好处之一。当然,javascript可以重置字段。这是另一个不需要任何其他内容的简单解决方案,将其添加到 app/views/layouts/devise_layout.html.erb 的标题中:

      <meta http-equiv="refresh" content="3600;URL='/users/sign_in'"/>
      

      【讨论】:

        猜你喜欢
        • 2017-07-15
        • 2015-07-24
        • 2011-11-15
        • 2014-06-16
        • 2012-05-08
        • 2015-12-29
        • 2023-03-26
        • 2016-09-17
        • 2012-12-11
        相关资源
        最近更新 更多