使用Rails 3.2.11和RSpec发布原始JSON数据

Dan*_*uis 44 json ruby-on-rails rspec2 rspec-rails ruby-on-rails-3.2

为了确保我的应用程序不容易受到这种攻击,我试图在RSpec中创建一个控制器测试来覆盖它.为了做到这一点,我需要能够发布原始JSON,但我似乎没有找到一种方法来做到这一点.在进行一些研究时,我已经确定使用RAW_POST_DATA标题至少有一种方法可以这样做,但这似乎不再起作用了:

it "should not be exploitable by using an integer token value" do
  request.env["CONTENT_TYPE"] = "application/json"
  request.env["RAW_POST_DATA"]  = { token: 0 }.to_json
  post :reset_password
end
Run Code Online (Sandbox Code Playgroud)

当我查看params散列时,令牌根本没有设置,它只包含{ "controller" => "user", "action" => "reset_password" }.我在尝试使用XML时得到了相同的结果,或者甚至在尝试使用常规的帖子数据时,在所有情况下,它似乎都没有设置它的周期.

我知道,随着最近的Rails漏洞,参数被散列的方式发生了变化,但仍有办法通过RSpec发布原始数据吗?我可以以某种方式直接使用Rack::Test::Methods

Dan*_*uis 75

据我所知,在控制器规范中不再可能发送原始POST数据.但是,它可以在请求规范中很容易地完成:

describe "Example", :type => :request do
  params = { token: 0 }
  post "/user/reset_password", params.to_json, { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
  #=> params contains { "controller" => "user", "action" => "reset_password", "token" => 0 }
end
Run Code Online (Sandbox Code Playgroud)

  • 在Rails 3.2.13中,这个解决方案对我不起作用.我的解决方法是编写`params = {token:0,format :: json}`.同时在示例中删除.to_json及其后面的哈希.您也可能希望在`spec_helper.rb`中使用`config.include Rails.application.routes.url_helpers`.使用`response.header ['Content-Type']验证json响应.应该包含'application/json' (15认同)
  • 我喜欢这样:使用Rails 3.2.14发布"/ user/reset_password",params.merge(格式:'json') (3认同)

mas*_*sta 11

这是将原始JSON发送到控制器操作(Rails 3+)的方法:

假设我们有这样的路线:

post "/users/:username/posts" => "posts#create"

而且,假设您希望身体成为您通过以下方式阅读的json:

JSON.parse(request.body.read)

然后你的测试看起来像这样:

it "should create a post from a json body" do
  json_payload = '{"message": "My opinion is very important"}'
  post :create, json_payload, {format: 'json', username: "larry" }
end
Run Code Online (Sandbox Code Playgroud)

{format: 'json'}是让它成为现实的魔力.另外,如果我们查看TestCase的来源#post http://api.rubyonrails.org/classes/ActionController/TestCase/Behavior.html#method-i-process,您可以看到它在动作之后需要第一个参数( json_payload)并且如果它是一个字符串,它将其设置为原始帖子体,并正常解析其余的args.

同样重要的是要指出rspec只是Rails测试架构之上的DSL.post上面的方法是ActionController :: TestCase#post而不是某些rspec发明.


and*_*ell 10

我们在控制器测试中所做的是显式设置RAW_POST_DATA:

before do
  @request.env['RAW_POST_DATA'] = payload.to_json
  post :my_action
end
Run Code Online (Sandbox Code Playgroud)


Jer*_*nch 8

Rails 5示例:

RSpec.describe "Sessions responds to JSON", :type => :request do

  scenario 'with correct authentication' do
    params = {id: 1, format: :json}
    post "/users/sign_in", params: params.to_json, headers: { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
    expect(response.header['Content-Type']).to include 'application/json'
  end
end
Run Code Online (Sandbox Code Playgroud)


qqb*_*enq 5

以下是发送原始json数据的控制器测试的完整工作示例:

describe UsersController, :type => :controller do

  describe "#update" do
    context 'when resource is found' do
      before(:each) do
        @user = FactoryGirl.create(:user)
      end

      it 'updates the resource with valid data' do
        @request.headers['Content-Type'] = 'application/vnd.api+json'
        old_email = @user.email
        new_email = Faker::Internet.email
        jsondata = 
        {
          "data" => {
            "type" => "users",
            "id" => @user.id,
            "attributes" => {
              "email" => new_email
            }
          }
        }

        patch :update, jsondata.to_json, jsondata.merge({:id => old_id})

        expect(response.status).to eq(200)
        json_response = JSON.parse(response.body)
        expect(json_response['data']['id']).to eq(@user.id)
        expect(json_response['data']['attributes']['email']).to eq(new_email)
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

重要的部分是:

@request.headers['Content-Type'] = 'application/vnd.api+json'
Run Code Online (Sandbox Code Playgroud)

patch :update, jsondata.to_json, jsondata.merge({:id => old_id})
Run Code Online (Sandbox Code Playgroud)

第一个确保为您的请求正确设置内容类型,这非常简单.第二部分让我头疼几个小时,我的初始方法有点不同,但事实证明有一个Rails错误,这阻止我们在功能测试中发送原始发布数据(但允许我们进行集成测试),这是一个丑陋的解决方法,但它的工作原理(在rails 4.1.8和rspec-rails 3.0.0上).