Fix XSS vulnerabilities in chunk-handling
This commit is contained in:
parent
36b86a9d41
commit
a3d3f1c536
|
@ -16,7 +16,8 @@ class Category < Chunk::Abstract
|
||||||
def initialize(match_data, content)
|
def initialize(match_data, content)
|
||||||
super(match_data, content)
|
super(match_data, content)
|
||||||
@hidden = match_data[1]
|
@hidden = match_data[1]
|
||||||
@list = match_data[2].split(',').map { |c| c.strip }
|
@list = match_data[2].split(',').map { |c| c.to_s.is_utf8? ? html_escape(c. strip) : nil }
|
||||||
|
@list.compact!
|
||||||
@unmask_text = ''
|
@unmask_text = ''
|
||||||
if @hidden
|
if @hidden
|
||||||
@unmask_text = ''
|
@unmask_text = ''
|
||||||
|
@ -28,6 +29,6 @@ def initialize(match_data, content)
|
||||||
|
|
||||||
# TODO move presentation of page metadata to controller/view
|
# TODO move presentation of page metadata to controller/view
|
||||||
def url(category)
|
def url(category)
|
||||||
%{<a class="category_link" href="../list/?category=#{category}">#{category}</a>}
|
%{<a class="category_link" href="../list/#{category}">#{category}</a>}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -74,6 +74,14 @@ module Chunk
|
||||||
@content.delete_chunk(self)
|
@content.delete_chunk(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def html_escape(string)
|
||||||
|
string.gsub( /&/, "&" ).
|
||||||
|
gsub( /</, "<" ).
|
||||||
|
gsub( />/, ">" ).
|
||||||
|
gsub( /'/, "'" ).
|
||||||
|
gsub( /"/, """ )
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,10 @@ require 'chunks/chunk'
|
||||||
#
|
#
|
||||||
# Author: Mark Reid <mark at threewordslong dot com>
|
# Author: Mark Reid <mark at threewordslong dot com>
|
||||||
# Created: 8th June 2004
|
# Created: 8th June 2004
|
||||||
|
|
||||||
|
require 'sanitize'
|
||||||
|
include Sanitize
|
||||||
|
|
||||||
class NoWiki < Chunk::Abstract
|
class NoWiki < Chunk::Abstract
|
||||||
|
|
||||||
NOWIKI_PATTERN = Regexp.new('<nowiki>(.*?)</nowiki>', Regexp::MULTILINE)
|
NOWIKI_PATTERN = Regexp.new('<nowiki>(.*?)</nowiki>', Regexp::MULTILINE)
|
||||||
|
@ -22,7 +26,7 @@ class NoWiki < Chunk::Abstract
|
||||||
|
|
||||||
def initialize(match_data, content)
|
def initialize(match_data, content)
|
||||||
super
|
super
|
||||||
@plain_text = @unmask_text = match_data[1]
|
@plain_text = @unmask_text = sanitize_html(match_data[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -203,3 +203,28 @@ module Sanitize
|
||||||
style = clean.join(' ')
|
style = clean.join(' ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Some useful additions to the String class
|
||||||
|
|
||||||
|
class String
|
||||||
|
|
||||||
|
# Check whether a string is valid utf-8
|
||||||
|
#
|
||||||
|
# :call-seq:
|
||||||
|
# string.is_utf8? -> boolean
|
||||||
|
#
|
||||||
|
# returns true if the sequence of bytes in string is valid utf-8
|
||||||
|
def is_utf8?
|
||||||
|
self =~ /^(
|
||||||
|
[\x09\x0A\x0D\x20-\x7E] # ASCII
|
||||||
|
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|
||||||
|
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|
||||||
|
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|
||||||
|
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|
||||||
|
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|
||||||
|
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|
||||||
|
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
|
||||||
|
)*$/x;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -19,4 +19,12 @@ class CategoryTest < Test::Unit::TestCase
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_multiple_categories_sanitized
|
||||||
|
match(Category, 'category: test, multiple,<span>a & b</span> <script>alert("XSS!");</script>', :list => ['test', 'multiple', '<span>a & b</span> <script>alert("XSS!");</script>'], :hidden => nil
|
||||||
|
)
|
||||||
|
match(Category, 'category : chunk test , multi category,<span>a & b</span> <script>alert("XSS!");</script>',
|
||||||
|
:list => ['chunk test','multi category','<span>a & b</span> <script>alert("XSS!");</script>'], :hidden => nil
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,4 +12,10 @@ class NoWikiTest < Test::Unit::TestCase
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_sanitized_nowiki
|
||||||
|
match(NoWiki, 'This sentence contains <nowiki><span>a b</span> <script>alert("XSS!");</script></nowiki>. Do not touch!',
|
||||||
|
:plain_text => '<span>a b</span> <script>alert("XSS!");</script>'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue