Project

General

Profile

Feature #32424 » 0006-CommonMark-remove-extensive-link-target-restriction.patch

Fixing the same issue like in #32766 - Martin Cizek, 2021-04-17 19:28

View differences:

lib/redmine/helpers/url.rb
22 22
module Redmine
23 23
  module Helpers
24 24
    module URL
25
      # safe for resources fetched without user interaction?
25 26
      def uri_with_safe_scheme?(uri, schemes = ['http', 'https', 'ftp', 'mailto', nil])
26 27
        # URLs relative to the current document or document root (without a protocol
27 28
        # separator, should be harmless
......
32 33
      rescue URI::Error
33 34
        false
34 35
      end
36

  
37
      # safe to render links to given uri?
38
      def uri_with_link_safe_scheme?(uri)
39
        # regexp adapted from Sanitize (we need to catch even invalid protocol specs)
40
        return true unless uri =~ /\A\s*([^\/#]*?)(?:\:|&#0*58|&#x0*3a)/i
41
        # absolute scheme
42
        scheme = $1.downcase
43
        return false unless scheme =~ /\A[a-z][a-z0-9\+\.\-]*\z/ # RFC 3986
44
        %w(data javascript vbscript).none?(scheme)
45
      end
35 46
    end
36 47
  end
37 48
end
lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
24 24

  
25 25
      # sanitizes rendered HTML using the Sanitize gem
26 26
      class SanitizationFilter < HTML::Pipeline::SanitizationFilter
27
        include Redmine::Helpers::URL
28

  
29
        RELAXED_PROTOCOL_ATTRS = {
30
          "a" => %w(href).freeze,
31
        }.freeze
32

  
27 33
        def whitelist
28 34
          @@whitelist ||= customize_whitelist(super.deep_dup)
29 35
        end
......
72 78
            node.remove_attribute("id")
73 79
          }
74 80

  
75
          # allw the same set of URL schemes for links as is the default in
76
          # Redmine::Helpers::URL#uri_with_safe_scheme?
77
          whitelist[:protocols][:a] = [
78
            'http', 'https', 'ftp', 'mailto', :relative
79
          ]
81
          # https://github.com/rgrove/sanitize/issues/209
82
          whitelist[:protocols].delete("a")
83
          whitelist[:transformers].push lambda{|env|
84
            node = env[:node]
85
            return if node.type != Nokogiri::XML::Node::ELEMENT_NODE
86
            name = env[:node_name]
87
            return unless RELAXED_PROTOCOL_ATTRS.include?(name)
88
            RELAXED_PROTOCOL_ATTRS[name].each do |attr|
89
              next unless node.has_attribute?(attr)
90
              node[attr] = node[attr].strip
91
              unless !node[attr].empty? && uri_with_link_safe_scheme?(node[attr])
92
                node.remove_attribute(attr)
93
              end
94
            end
95
          }
80 96

  
81 97
          whitelist
82 98
        end
test/unit/lib/redmine/helpers/url_test.rb
33 33
    assert_not uri_with_safe_scheme?("httpx://example.com/")
34 34
    assert_not uri_with_safe_scheme?("mailto:root@")
35 35
  end
36

  
37
  LINK_SAFE_URIS = [
38
    "http://example.com/",
39
    "https://example.com/",
40
    "ftp://example.com/",
41
    "foo://example.org",
42
    "mailto:foo@example.org",
43
    " http://example.com/",
44
    "",
45
    "/javascript:alert(\'filename\')",
46
  ]
47
  def test_uri_with_link_safe_scheme_should_recognize_safe_uris
48
    LINK_SAFE_URIS.each do |uri|
49
      assert uri_with_link_safe_scheme?(uri), "'#{uri}' should be safe"
50
    end
51
  end
52

  
53
  LINK_UNSAFE_URIS = [
54
    "javascript:alert(\'XSS\');",
55
    "javascript    :alert(\'XSS\');",
56
    "javascript:    alert(\'XSS\');",
57
    "javascript    :   alert(\'XSS\');",
58
    ":javascript:alert(\'XSS\');",
59
    "javascript&#58;",
60
    "javascript&#0058;",
61
    "javascript&#x3A;",
62
    "javascript&#x003A;",
63
    "java\0script:alert(\"XSS\")",
64
    "java\script:alert(\"XSS\")",
65
    " \x0e  javascript:alert(\'XSS\');",
66
    "data:image/png;base64,foobar",
67
    "vbscript:foobar",
68
    "data:text/html;base64,foobar",
69
  ]
70
  def test_uri_with_link_safe_scheme_should_recognize_unsafe_uris
71
    LINK_UNSAFE_URIS.each do |uri|
72
      assert_not uri_with_link_safe_scheme?(uri), "'#{uri}' should not be safe"
73
    end
74
  end
36 75
end
test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
54 54
    assert_equal %(<code>foo</code>), filter(input)
55 55
  end
56 56

  
57
  def test_should_allow_links_with_safe_url_schemes
58
    %w(http https ftp ssh foo).each do |scheme|
59
      input = %(<a href="#{scheme}://example.org/">foo</a>)
60
      assert_equal input, filter(input)
61
    end
62
  end
63

  
64
  def test_should_allow_mailto_links
65
    input = %(<a href="mailto:foo@example.org">bar</a>)
66
    assert_equal input, filter(input)
67
  end
68

  
69
  def test_should_remove_empty_link
70
    input = %(<a href="">bar</a>)
71
    assert_equal %(<a>bar</a>), filter(input)
72

  
73
    input = %(<a href=" ">bar</a>)
74
    assert_equal %(<a>bar</a>), filter(input)
75
  end
57 76

  
58 77
  # samples taken from the Sanitize test suite
59 78
  STRINGS = [
......
174 193
      '<a href="vbscript:foobar">XSS</a>',
175 194
      '<a>XSS</a>'
176 195
    ],
177

  
178
    'invalid URIs' => [
179
      '<a href="foo://example.org">link</a>',
180
      '<a>link</a>'
181
    ],
182 196
  }
183 197

  
184 198
  PROTOCOLS.each do |name, strings|
(6-6/26)