【问题标题】:rspec rails testing session_idrspec rails 测试 session_id
【发布时间】:2016-05-24 18:35:56
【问题描述】:

我有一件很奇怪的事情要测试。 最近,在存储会话信息方面,我们已从 cookie-storage 更改为 active-record-storage。这样做是为了防止在用户注销后使用 cookie 中的 session_id 继续浏览会话(这是您在使用 cookie-storage 时需要遗憾地接受的事情)。

现在我需要编写一些代码来测试迁移到 active-record-storage 是否确实解决了这个安全问题,但我不知道如何。

场景是这样的:

用户 signs in 到应用程序

应用的用户signs out

请求头中的session_id 然后用于获取请求以查看通常需要身份验证的应用程序部分 这应该是不可能的,因为我们没有经过身份验证(尽管我们使用了上一个请求中的 session_id)

我们希望得到 401、404 或 200 以外的任何其他值。

到目前为止,我已经设法从请求中获取 session_id -> @request.env["rack.sesion.options"][:id]

但我不知道如何使用并将此session_id 放入下一个请求中

有什么想法吗?

【问题讨论】:

  • 你试过rack_session_access吗?
  • 不,但对于我的情况来说,它似乎是一个不错的宝石。会试一试的!
  • 您是否在注销方法中使用reset_session
  • 不,我没有使用它
  • 那是你的问题 - 不是 SessionStorage。

标签: ruby-on-rails session rspec


【解决方案1】:

我认为你有点误会了。如果正确完成,即使使用 cookie-storage 也会永久注销。

一个会话通常由一个哈希值和一个会话 ID 组成, 通常是一个 32 个字符的字符串,用于标识哈希。每个发送的 cookie 到客户端的浏览器包括会话 id。而另一种方式 round:浏览器将在每次请求时将其发送到服务器 客户。
The Rails Guides - Securing Rails Applications

因此,要在注销时使用户会话无效,您需要调用 reset_session。这会发出一个新的会话 id 并使旧的无效 - 在服务器上。

请求标头中的 session_id 然后用于获取请求以查看 通常需要身份验证的应用程序的一部分,这不应该 是可能的,因为我们没有经过身份验证(尽管我们使用 session_id 来自上一个请求)

使用reset_session 会使上述情况变得不可能,因为rails 将不再接受旧的会话ID。当使用 cookie-storage 时,这意味着包含旧会话 id 的用户 cookie 将不再被接受 - 相同的基本原则适用于其他会话存储机制。除了对于某些会话存储,陈旧的数据也可能会被删除。

class SessionsController < ApplicationController

  def new
  end

  def create
    reset_session # prevents session fixation
    @user = User.find(params[:email])
    if @user.try(:authenticate, params[:password])
      session[:user_id] = @user.id
      redirect_to root_path
    else
      render :new, status: :not_found
    end
  end

  def destroy
    reset_session
    redirect_to root_path
  end
end

[对抗会话固定]最有效的对策是 发出一个新的会话标识符并在一个之后声明旧的无效 成功登录。这样,攻击者就无法使用固定会话 标识符。这是针对会话劫持的一个很好的对策, 也是。 The Rails Guides - Securing Rails Applications

如何测试?

最简单、最简洁的方法是使用功能规范:

require 'rails_helper'
RSpec.feature "User Authentiation" do

  context "signing out" do
    let(:user) { FactoryGirl.create(:user) }
    before do
      visit new_session_path
      fill_in :email, with: user.email
      fill_in :password: with: user.password
      click_button 'Log in'
      click_button 'Log out'
    end

    scenario 'user should not be signed in' do
      expect(page).to have_link 'Sign in'
      expect(page).to_not have_link 'Sign Out'
    end

    scenario 'user should not be able to access the member area' do
      visit '/members-only'
      expect(current_path).to_not eq '/members-only'
      expect(page).to have_text 'Please sign in'
    end
  end

  # ...
end

这避免了测试底层会话机制,而是专注于测试应用程序的行为。

如果您需要比使用请求规范更低级别的测试。不要使用控制器规范,因为它们会伪造整个请求和机架层。

【讨论】:

  • 嗨 -> 当我们使用 cookie 存储时,我已经尝试使用 reset_session,但也许我做错了?将尝试检查您的答案并检查其工作原理并更新结果。感谢您如此广泛的回复
  • 你好,为了回应你的回答 -> 我已经将 reset_session 放在了我们 session_controller 的销毁操作中(它实际上是一个设计会话控制器)我如何验证它对我的情况没有帮助?
  • 1.登录到应用程序 2. 在 chrome -> 网络中打开开发人员工具 3. 注销应用程序 4. 在开发工具的网络选项卡中我查找 sign_out 数据包/cookie/文件(我不确定它在技术上是如何被调用的) 5. 在 Cookie 部分的 sign_out 标头中,我看到了我的 session_id (my_app_name_session) 6. 我复制它并打开允许我发送 REST 请求的 chrom rest 客户端 7. 我在我的 REST GET 请求中填写了 Cookie 部分进入我的应用程序 url,要求用户进行身份验证
  • 8.我得到 200 OK 的响应,解析后的响应是我的目标视图的 html 输出如果您在我的检查方法中发现任何错误,请纠正我
猜你喜欢
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多