diff options
-rw-r--r-- | lib/redmine/helpers/url.rb | 15 | ||||
-rw-r--r-- | test/unit/lib/redmine/helpers/url_test.rb | 41 |
2 files changed, 56 insertions, 0 deletions
diff --git a/lib/redmine/helpers/url.rb b/lib/redmine/helpers/url.rb index 54fd3cb61..f56920b48 100644 --- a/lib/redmine/helpers/url.rb +++ b/lib/redmine/helpers/url.rb @@ -22,6 +22,7 @@ require 'uri' module Redmine module Helpers module URL + # safe for resources fetched without user interaction? def uri_with_safe_scheme?(uri, schemes = ['http', 'https', 'ftp', 'mailto', nil]) # URLs relative to the current document or document root (without a protocol # separator, should be harmless @@ -32,6 +33,20 @@ module Redmine rescue URI::Error false end + + # safe to render links to given uri? + def uri_with_link_safe_scheme?(uri) + # regexp adapted from Sanitize (we need to catch even invalid protocol specs) + return true unless uri =~ /\A\s*([^\/#]*?)(?:\:|�*58|�*3a)/i + + # absolute scheme + scheme = $1.downcase + return false unless /\A[a-z][a-z0-9\+\.\-]*\z/.match?(scheme) # RFC 3986 + + # To support Ruby 2.4, we use `none? {|obj| ... }` instead of + # `none?(pattern)` in 4.2-stable branch. + %w(data javascript vbscript).none? {|v| v == scheme} + end end end end diff --git a/test/unit/lib/redmine/helpers/url_test.rb b/test/unit/lib/redmine/helpers/url_test.rb index fe143393b..93a797a10 100644 --- a/test/unit/lib/redmine/helpers/url_test.rb +++ b/test/unit/lib/redmine/helpers/url_test.rb @@ -33,4 +33,45 @@ class URLTest < ActiveSupport::TestCase assert_not uri_with_safe_scheme?("httpx://example.com/") assert_not uri_with_safe_scheme?("mailto:root@") end + + LINK_SAFE_URIS = [ + "http://example.com/", + "https://example.com/", + "ftp://example.com/", + "foo://example.org", + "mailto:foo@example.org", + " http://example.com/", + "", + "/javascript:alert(\'filename\')", + ] + + def test_uri_with_link_safe_scheme_should_recognize_safe_uris + LINK_SAFE_URIS.each do |uri| + assert uri_with_link_safe_scheme?(uri), "'#{uri}' should be safe" + end + end + + LINK_UNSAFE_URIS = [ + "javascript:alert(\'XSS\');", + "javascript :alert(\'XSS\');", + "javascript: alert(\'XSS\');", + "javascript : alert(\'XSS\');", + ":javascript:alert(\'XSS\');", + "javascript:", + "javascript:", + "javascript:", + "javascript:", + "java\0script:alert(\"XSS\")", + "java\script:alert(\"XSS\")", + " \x0e javascript:alert(\'XSS\');", + "data:image/png;base64,foobar", + "vbscript:foobar", + "data:text/html;base64,foobar", + ] + + def test_uri_with_link_safe_scheme_should_recognize_unsafe_uris + LINK_UNSAFE_URIS.each do |uri| + assert_not uri_with_link_safe_scheme?(uri), "'#{uri}' should not be safe" + end + end end |