rspec rails测试session_id

时间:2016-05-24 09:06:44

标签: ruby-on-rails session rspec

我有一个非常特殊的东西需要测试。 最近,在存储会话信息时,我们已经从cookie存储更改为活动记录存储。这样做是为了防止使用cookies中的session_id继续浏览会话,即使在用户注销后也是如此(在使用cookie存储时,您需要遗憾地接受这一点)。

现在我需要编写一些代码来测试是否转移到活动记录存储确实解决了这个安全问题,但我不知道如何。

情景是:

用户signs in到应用

应用的用户signs out

然后,在请求标头中使用

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

我们希望获得401,或404或200以外的其他任何东西。

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

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

任何想法?

1 个答案:

答案 0 :(得分:0)

我觉得你有些误解了。如果正确完成注销,即使使用cookie存储也是永久性的。

  

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

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

  然后,在请求查看中使用来自请求标头的

session_id   通常需要身份验证的应用程序的一部分,不应该   是可能的,因为我们没有经过身份验证(尽管我们使用的是   来自先前请求的session_id)

使用reset_session无法呈现上述方案,因为rails将不再接受旧的会话ID。使用cookie存储时,这意味着将不再接受包含旧会话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

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

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