]> source.dussan.org Git - redmine.git/commitdiff
Backport `Redmine::Helpers::URL#uri_with_link_safe_scheme?` from r21161 to 4.2-stable...
authorGo MAEDA <maeda@farend.jp>
Mon, 18 Sep 2023 06:28:42 +0000 (06:28 +0000)
committerGo MAEDA <maeda@farend.jp>
Mon, 18 Sep 2023 06:28:42 +0000 (06:28 +0000)
git-svn-id: https://svn.redmine.org/redmine/branches/4.2-stable@22300 e93f8b46-1217-0410-a6f0-8f06a7374b81

lib/redmine/helpers/url.rb
test/unit/lib/redmine/helpers/url_test.rb

index 54fd3cb6184aa85493db2c75e5f1eeca9dd7483d..f56920b489e2f50fdfbe3428218c5d522a35e506 100644 (file)
@@ -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*([^\/#]*?)(?:\:|&#0*58|&#x0*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
index fe143393b85dd2017e8bc42cb311a5e50dbea037..93a797a1077bd98c94ef1952a8bf4537dbfea3dc 100644 (file)
@@ -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&#58;",
+    "javascript&#0058;",
+    "javascript&#x3A;",
+    "javascript&#x003A;",
+    "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