Avoid redirects with unprotected query params

In theory it's possible to add a `host` parameter to a URL, and we could
end up redirecting to that host if we just redirect using query
parameters.

Generating the path using `url_for` with `only_path` solves the issue.

Note in the tests I'm using the `get` method because the `patch` method
wouldn't send query parameters. This doesn't mean the action can be
accessed through GET requests, since controller tests don't check route
verbs. Using feature specs doesn't seem to work because `controller` and
`host` parameters are filtered automatically in feature specs.

Also note I'm not testing every hidden/moderation controller because
they basically use the same code.
This commit is contained in:
Javi Martín
2019-11-10 15:27:20 +01:00
parent 667797161b
commit 50bdfd5488
5 changed files with 84 additions and 1 deletions

View File

@@ -122,6 +122,9 @@ class ApplicationController < ActionController::Base
end
def redirect_with_query_params_to(options, response_status = {})
redirect_to request.query_parameters.merge(options), response_status
path_options = { controller: params[:controller] }.merge(options).merge(only_path: true)
path = url_for(request.query_parameters.merge(path_options))
redirect_to path, response_status
end
end

View File

@@ -0,0 +1,25 @@
require "rails_helper"
describe Admin::HiddenDebatesController do
before { sign_in create(:administrator).user }
describe "PUT confirm_hide" do
it "keeps query parameters while using protected redirects" do
debate = create(:debate, :hidden)
get :confirm_hide, params: { id: debate, filter: "all", host: "evil.dev" }
expect(response).to redirect_to "/admin/hidden_debates?filter=all"
end
end
describe "PUT restore" do
it "keeps query parameters while using protected redirects" do
debate = create(:debate, :hidden, :with_confirmed_hide)
get :restore, params: { id: debate, filter: "all", host: "evil.dev" }
expect(response).to redirect_to "/admin/hidden_debates?filter=all"
end
end
end

View File

@@ -0,0 +1,25 @@
require "rails_helper"
describe Admin::OrganizationsController do
before { sign_in create(:administrator).user }
describe "PUT verify" do
it "keeps query parameters while using protected redirects" do
organization = create(:organization)
get :verify, params: { id: organization, filter: "pending", host: "evil.dev" }
expect(response).to redirect_to "/admin/organizations?filter=pending"
end
end
describe "PUT reject" do
it "keeps query parameters while using protected redirects" do
organization = create(:organization)
get :reject, params: { id: organization, filter: "pending", host: "evil.dev" }
expect(response).to redirect_to "/admin/organizations?filter=pending"
end
end
end

View File

@@ -0,0 +1,15 @@
require "rails_helper"
describe Moderation::Budgets::InvestmentsController do
before { sign_in create(:moderator).user }
describe "PUT moderate" do
it "keeps query parameters while using protected redirects" do
id = create(:budget_investment).id
get :moderate, params: { resource_ids: [id], filter: "all", host: "evil.dev" }
expect(response).to redirect_to "/moderation/budget_investments?filter=all&resource_ids%5B%5D=#{id}"
end
end
end

View File

@@ -0,0 +1,15 @@
require "rails_helper"
describe Moderation::UsersController do
before { sign_in create(:moderator).user }
describe "PUT hide_in_moderation_screen" do
it "keeps query parameters while using protected redirects" do
user = create(:user, email: "user@consul.dev")
get :hide_in_moderation_screen, params: { id: user, name_or_email: "user@consul.dev", host: "evil.dev" }
expect(response).to redirect_to "/moderation/users?name_or_email=user%40consul.dev"
end
end
end