aboutsummaryrefslogtreecommitdiffstats
path: root/actionview
diff options
context:
space:
mode:
authorDamien Burke <damien@damienburke.com>2015-11-03 17:17:10 -0800
committerDamien Burke <damien@damienburke.com>2015-11-03 17:20:48 -0800
commitab5fb4f22430afa58c334f7e7e142660164490e5 (patch)
treefbb50859955bddc1fa48dbe1667eb6ae1b8b1596 /actionview
parente37b470a6675a05df5a57455a3ac8c1c88ef04d6 (diff)
downloadrails-ab5fb4f22430afa58c334f7e7e142660164490e5.tar.gz
rails-ab5fb4f22430afa58c334f7e7e142660164490e5.tar.bz2
rails-ab5fb4f22430afa58c334f7e7e142660164490e5.zip
Don’t allow arbitrary data in back urls
`link_to :back` creates a link to whatever was passed in via the referer header. If an attacker can alter the referer header, that would create a cross-site scripting vulnerability on every page that uses `link_to :back` This commit restricts the back URL to valid non-javascript URLs. https://github.com/rails/rails/issues/14444
Diffstat (limited to 'actionview')
-rw-r--r--actionview/CHANGELOG.md4
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb14
-rw-r--r--actionview/test/template/url_helper_test.rb17
3 files changed, 33 insertions, 2 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 65314184c8..e5f5961326 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Restrict `url_for :back` to valid, non-JavaScript URLs. GH#14444
+
+ *Damien Burke*
+
* Allow `date_select` helper selected option to accept hash like the default options.
*Lecky Lao*
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index 5684de35e8..baebc34b4b 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -41,11 +41,21 @@ module ActionView
end
def _back_url # :nodoc:
- referrer = controller.respond_to?(:request) && controller.request.env["HTTP_REFERER"]
- referrer || 'javascript:history.back()'
+ _filtered_referrer || 'javascript:history.back()'
end
protected :_back_url
+ def _filtered_referrer # :nodoc:
+ if controller.respond_to?(:request)
+ referrer = controller.request.env["HTTP_REFERER"]
+ if referrer && URI(referrer).scheme != 'javascript'
+ referrer
+ end
+ end
+ rescue URI::InvalidURIError
+ end
+ protected :_filtered_referrer
+
# Creates an anchor element of the given +name+ using a URL created by the set of +options+.
# See the valid options in the documentation for +url_for+. It's also possible to
# pass a String instead of an options hash, which generates an anchor element that uses the
diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb
index 43a65a58cb..48d0a9a47a 100644
--- a/actionview/test/template/url_helper_test.rb
+++ b/actionview/test/template/url_helper_test.rb
@@ -50,6 +50,23 @@ class UrlHelperTest < ActiveSupport::TestCase
assert_equal 'javascript:history.back()', url_for(:back)
end
+ def test_url_for_with_back_and_no_controller
+ @controller = nil
+ assert_equal 'javascript:history.back()', url_for(:back)
+ end
+
+ def test_url_for_with_back_and_javascript_referer
+ referer = 'javascript:alert(document.cookie)'
+ @controller = Struct.new(:request).new(Struct.new(:env).new("HTTP_REFERER" => referer))
+ assert_equal 'javascript:history.back()', url_for(:back)
+ end
+
+ def test_url_for_with_invalid_referer
+ referer = 'THIS IS NOT A URL'
+ @controller = Struct.new(:request).new(Struct.new(:env).new("HTTP_REFERER" => referer))
+ assert_equal 'javascript:history.back()', url_for(:back)
+ end
+
def test_button_to_with_straight_url
assert_dom_equal %{<form method="post" action="http://www.example.com" class="button_to"><input type="submit" value="Hello" /></form>}, button_to("Hello", "http://www.example.com")
end