Merge pull request #32770 from zealot128/patch-2

Request Forgery takes relative paths into account
This commit is contained in:
Rafael Mendonça França 2024-02-21 12:16:54 -05:00 committed by GitHub
commit db4c6db59d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 52 additions and 0 deletions

View File

@ -1,3 +1,7 @@
* Request Forgery takes relative paths into account.
*Stefan Wienert*
* Add ".test" as a default allowed host in development to ensure smooth golden-path setup with puma.dev.
*DHH*

View File

@ -635,6 +635,15 @@ module ActionController # :nodoc:
def normalize_action_path(action_path) # :doc:
uri = URI.parse(action_path)
if uri.relative? && (action_path.blank? || !action_path.start_with?("/"))
uri = URI.parse(request.path)
# add the action path to the request.path
uri.path += "/#{action_path}"
# relative path with "./path"
uri.path.gsub!("/./", "/")
end
uri.path.chomp("/")
end

View File

@ -1112,6 +1112,45 @@ class PerFormTokensControllerTest < ActionController::TestCase
assert_response :success
end
def test_handles_empty_path_as_request_path
get :index, params: { form_path: "" }
form_token = assert_presence_and_fetch_form_csrf_token
# This is required because PATH_INFO isn't reset between requests.
@request.env["PATH_INFO"] = "/per_form_tokens"
assert_nothing_raised do
post :post_one, params: { custom_authenticity_token: form_token }
end
assert_response :success
end
def test_handles_relative_paths
get :index, params: { form_path: "post_one" }
form_token = assert_presence_and_fetch_form_csrf_token
# This is required because PATH_INFO isn't reset between requests.
@request.env["PATH_INFO"] = "/per_form_tokens/post_one"
assert_nothing_raised do
post :post_one, params: { custom_authenticity_token: form_token }
end
assert_response :success
end
def test_handles_relative_paths_with_dot
get :index, params: { form_path: "./post_one" }
form_token = assert_presence_and_fetch_form_csrf_token
# This is required because PATH_INFO isn't reset between requests.
@request.env["PATH_INFO"] = "/per_form_tokens/post_one"
assert_nothing_raised do
post :post_one, params: { custom_authenticity_token: form_token }
end
assert_response :success
end
def test_ignores_origin_during_generation
get :index, params: { form_path: "https://example.com/per_form_tokens/post_one/" }