Skip to content

Commit 0125ba1

Browse files
committed
Don't redirect to another suburi (#16530).
git-svn-id: http://svn.redmine.org/redmine/trunk@13213 e93f8b46-1217-0410-a6f0-8f06a7374b81
1 parent 1b01a7a commit 0125ba1

File tree

2 files changed

+67
-12
lines changed

2 files changed

+67
-12
lines changed

app/controllers/application_controller.rb

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -376,18 +376,9 @@ def back_url
376376

377377
def redirect_back_or_default(default, options={})
378378
back_url = params[:back_url].to_s
379-
if back_url.present?
380-
begin
381-
uri = URI.parse(back_url)
382-
# do not redirect user to another host or to the login or register page
383-
if ((uri.relative? && back_url.match(%r{\A/(\w.*)?\z})) || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)})
384-
redirect_to(back_url)
385-
return
386-
end
387-
rescue URI::InvalidURIError
388-
logger.warn("Could not redirect to invalid URL #{back_url}")
389-
# redirect to default
390-
end
379+
if back_url.present? && valid_back_url?(back_url)
380+
redirect_to(back_url)
381+
return
391382
elsif options[:referer]
392383
redirect_to_referer_or default
393384
return
@@ -396,6 +387,34 @@ def redirect_back_or_default(default, options={})
396387
false
397388
end
398389

390+
# Returns true if back_url is a valid url for redirection, otherwise false
391+
def valid_back_url?(back_url)
392+
if CGI.unescape(back_url).include?('..')
393+
return false
394+
end
395+
396+
begin
397+
uri = URI.parse(back_url)
398+
rescue URI::InvalidURIError
399+
return false
400+
end
401+
402+
if uri.host.present? && uri.host != request.host
403+
return false
404+
end
405+
406+
if uri.path.match(%r{/(login|account/register)})
407+
return false
408+
end
409+
410+
if relative_url_root.present? && !uri.path.starts_with?(relative_url_root)
411+
return false
412+
end
413+
414+
return true
415+
end
416+
private :valid_back_url?
417+
399418
# Redirects to the request referer if present, redirects to args or call block otherwise.
400419
def redirect_to_referer_or(*args, &block)
401420
redirect_to :back

test/functional/account_controller_test.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ def test_login_should_redirect_to_back_url_param
7171
end
7272
end
7373

74+
def test_login_with_suburi_should_redirect_to_back_url_param
75+
@relative_url_root = ApplicationController.relative_url_root
76+
ApplicationController.relative_url_root = '/redmine'
77+
78+
back_urls = [
79+
'http://test.host/redmine/issues/show/1',
80+
'/redmine'
81+
]
82+
back_urls.each do |back_url|
83+
post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
84+
assert_redirected_to back_url
85+
end
86+
ensure
87+
ApplicationController.relative_url_root = @relative_url_root
88+
end
89+
7490
def test_login_should_not_redirect_to_another_host
7591
back_urls = [
7692
'http://test.foo/fake',
@@ -82,6 +98,26 @@ def test_login_should_not_redirect_to_another_host
8298
end
8399
end
84100

101+
def test_login_with_suburi_should_not_redirect_to_another_suburi
102+
@relative_url_root = ApplicationController.relative_url_root
103+
ApplicationController.relative_url_root = '/redmine'
104+
105+
back_urls = [
106+
'http://test.host/',
107+
'http://test.host/fake',
108+
'http://test.host/fake/issues',
109+
'http://test.host/redmine/../fake',
110+
'http://test.host/redmine/../fake/issues',
111+
'http://test.host/redmine/%2e%2e/fake'
112+
]
113+
back_urls.each do |back_url|
114+
post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
115+
assert_redirected_to '/my/page'
116+
end
117+
ensure
118+
ApplicationController.relative_url_root = @relative_url_root
119+
end
120+
85121
def test_login_with_wrong_password
86122
post :login, :username => 'admin', :password => 'bad'
87123
assert_response :success

0 commit comments

Comments
 (0)