Changeset 7589
- Timestamp:
- 09/23/07 00:11:08 (2 years ago)
- Files:
-
- trunk/actionpack/CHANGELOG (modified) (1 diff)
- trunk/actionpack/lib/action_view/base.rb (modified) (1 diff)
- trunk/actionpack/lib/action_view/helpers/text_helper.rb (modified) (3 diffs)
- trunk/actionpack/test/template/text_helper_test.rb (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/actionpack/CHANGELOG
r7571 r7589 1 1 *SVN* 2 3 * Secure #sanitize, #strip_tags, and #strip_links helpers against xss attacks. Closes #8877. [Rick, lifofifo, Jacques Distler] 4 5 This merges and renames the popular white_list helper (along with some css sanitizing from Jacques Distler version of the same plugin). 6 Also applied updated versions of #strip_tags and #strip_links from #8877. 2 7 3 8 * Remove use of & logic operator. Closes #8114. [watson] trunk/actionpack/lib/action_view/base.rb
r7513 r7589 199 199 @@erb_variable = '_erbout' 200 200 cattr_accessor :erb_variable 201 202 # A regular expression of the valid characters used to separate protocols like 203 # the ':' in 'http://foo.com' 204 @@sanitized_protocol_separator = /:|(�*58)|(p)|(%|%)3A/ 205 cattr_accessor :sanitized_protocol_separator 206 207 # Specifies a Set of HTML attributes that can have URIs. 208 @@sanitized_uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc)) 209 cattr_reader :sanitized_uri_attributes 210 211 # Adds valid HTML attributes that the #sanitize helper checks for URIs. 212 # 213 # Rails::Initializer.run do |config| 214 # config.action_view.sanitized_uri_attributes = 'lowsrc', 'target' 215 # end 216 # 217 def self.sanitized_uri_attributes=(attributes) 218 @@sanitized_uri_attributes.merge(attributes) 219 end 220 221 # Specifies a Set of 'bad' tags that the #sanitize helper will remove completely, as opposed 222 # to just escaping harmless tags like <font> 223 @@sanitized_bad_tags = Set.new('script') 224 cattr_reader :sanitized_bad_tags 225 226 # Adds to the Set of 'bad' tags for the #sanitize helper. 227 # 228 # Rails::Initializer.run do |config| 229 # config.action_view.sanitized_bad_tags = 'embed', 'object' 230 # end 231 # 232 def self.sanitized_bad_tags=(attributes) 233 @@sanitized_bad_tags.merge(attributes) 234 end 235 236 # Specifies the default Set of tags that the #sanitize helper will allow unscathed. 237 @@sanitized_allowed_tags = Set.new(%w(strong em b i p code pre tt output samp kbd var sub 238 sup dfn cite big small address hr br div span h1 h2 h3 h4 h5 h6 ul ol li dt dd abbr 239 acronym a img blockquote del ins fieldset legend)) 240 cattr_reader :sanitized_allowed_tags 241 242 # Adds to the Set of allowed tags for the #sanitize helper. 243 # 244 # Rails::Initializer.run do |config| 245 # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td' 246 # end 247 # 248 def self.sanitized_allowed_tags=(attributes) 249 @@sanitized_allowed_tags.merge(attributes) 250 end 251 252 # Specifies the default Set of html attributes that the #sanitize helper will leave 253 # in the allowed tag. 254 @@sanitized_allowed_attributes = Set.new(%w(href src width height alt cite datetime title class name xml:lang abbr)) 255 cattr_reader :sanitized_allowed_attributes 256 257 # Adds to the Set of allowed html attributes for the #sanitize helper. 258 # 259 # Rails::Initializer.run do |config| 260 # config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc' 261 # end 262 # 263 def self.sanitized_allowed_attributes=(attributes) 264 @@sanitized_allowed_attributes.merge(attributes) 265 end 266 267 # Specifies the default Set of acceptable css properties that #sanitize and #sanitize_css will accept. 268 @@sanitized_allowed_css_properties = Set.new(%w(azimuth background-color border-bottom-color border-collapse 269 border-color border-left-color border-right-color border-top-color clear color cursor direction display 270 elevation float font font-family font-size font-style font-variant font-weight height letter-spacing line-height 271 overflow pause pause-after pause-before pitch pitch-range richness speak speak-header speak-numeral speak-punctuation 272 speech-rate stress text-align text-decoration text-indent unicode-bidi vertical-align voice-family volume white-space 273 width)) 274 cattr_reader :sanitized_allowed_css_properties 275 276 # Adds to the Set of allowed css properties for the #sanitize and #sanitize_css heleprs. 277 # 278 # Rails::Initializer.run do |config| 279 # config.action_view.sanitized_allowed_css_properties = 'expression' 280 # end 281 # 282 def self.sanitized_allowed_css_properties=(attributes) 283 @@sanitized_allowed_css_properties.merge(attributes) 284 end 285 286 # Specifies the default Set of acceptable css keywords that #sanitize and #sanitize_css will accept. 287 @@sanitized_allowed_css_keywords = Set.new(%w(auto aqua black block blue bold both bottom brown center 288 collapse dashed dotted fuchsia gray green !important italic left lime maroon medium none navy normal 289 nowrap olive pointer purple red right solid silver teal top transparent underline white yellow)) 290 cattr_reader :sanitized_allowed_css_keywords 291 292 # Adds to the Set of allowed css keywords for the #sanitize and #sanitize_css helpers. 293 # 294 # Rails::Initializer.run do |config| 295 # config.action_view.sanitized_allowed_css_keywords = 'expression' 296 # end 297 # 298 def self.sanitized_allowed_css_keywords=(attributes) 299 @@sanitized_allowed_css_keywords.merge(attributes) 300 end 301 302 # Specifies the default Set of allowed shorthand css properties for the #sanitize and #sanitize_css helpers. 303 @@sanitized_shorthand_css_properties = Set.new(%w(background border margin padding)) 304 cattr_reader :sanitized_shorthand_css_properties 305 306 # Adds to the Set of allowed shorthand css properties for the #sanitize and #sanitize_css helpers. 307 # 308 # Rails::Initializer.run do |config| 309 # config.action_view.sanitized_shorthand_css_properties = 'expression' 310 # end 311 # 312 def self.sanitized_shorthand_css_properties=(attributes) 313 @@sanitized_shorthand_css_properties.merge(attributes) 314 end 315 316 # Specifies the default Set of protocols that the #sanitize helper will leave in 317 # protocol attributes. 318 @@sanitized_allowed_protocols = Set.new(%w(ed2k ftp http https irc mailto news gopher nntp telnet webcal xmpp callto feed svn urn aim rsync tag ssh sftp rtsp afs)) 319 cattr_reader :sanitized_allowed_protocols 320 321 # Adds to the Set of allowed protocols for the #sanitize helper. 322 # 323 # Rails::Initializer.run do |config| 324 # config.action_view.sanitized_allowed_protocols = 'ssh', 'feed' 325 # end 326 # 327 def self.sanitized_allowed_protocols=(attributes) 328 @@sanitized_allowed_protocols.merge(attributes) 329 end 201 330 202 331 @@template_handlers = HashWithIndifferentAccess.new trunk/actionpack/lib/action_view/helpers/text_helper.rb
r7562 r7589 325 325 # strip_links('Blog: <a href="http://www.myblog.com/" class="nav" target=\"_blank\">Visit</a>.') 326 326 # # => Blog: Visit 327 def strip_links(text) 328 text.gsub(/<a\b.*?>(.*?)<\/a>/mi, '\1') 329 end 330 331 VERBOTEN_TAGS = %w(form script plaintext) unless defined?(VERBOTEN_TAGS) 332 VERBOTEN_ATTRS = /^on/i unless defined?(VERBOTEN_ATTRS) 333 334 # Sanitizes the +html+ by converting <form> and <script> tags into regular 335 # text, and removing all "on*" (e.g., onClick) attributes so that arbitrary Javascript 336 # cannot be executed. It also removes <tt>href</tt> and <tt>src</tt> attributes that start with 337 # "javascript:". You can modify what gets sanitized by defining VERBOTEN_TAGS 338 # and VERBOTEN_ATTRS before this Module is loaded. 339 # 340 # ==== Examples 341 # sanitize('<script> do_nasty_stuff() </script>') 342 # # => <script> do_nasty_stuff() </script> 343 # 344 # sanitize('<a href="javascript: sucker();">Click here for $100</a>') 345 # # => <a>Click here for $100</a> 346 # 347 # sanitize('<a href="#" onClick="kill_all_humans();">Click here!!!</a>') 348 # # => <a href="#">Click here!!!</a> 349 # 350 # sanitize('<img src="javascript:suckers_run_this();" />') 351 # # => <img /> 352 def sanitize(html) 353 # only do this if absolutely necessary 354 if html.index("<") 327 def strip_links(html) 328 # Stupid firefox treats '<href="http://whatever.com" onClick="alert()">something' as link! 329 if html.index("<a") || html.index("<href") 330 tokenizer = HTML::Tokenizer.new(html) 331 result = '' 332 while token = tokenizer.next 333 node = HTML::Node.parse(nil, 0, 0, token, false) 334 result << node.to_s unless node.is_a?(HTML::Tag) && ["a", "href"].include?(node.name) 335 end 336 strip_links(result) # Recurse - handle all dirty nested links 337 else 338 html 339 end 340 end 341 342 # This #sanitize helper will html encode all tags and strip all attributes that aren't specifically allowed. 343 # It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any 344 # tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out 345 # the extensive test suite. 346 # 347 # <%= sanitize @article.body %> 348 # 349 # You can add or remove tags/attributes if you want to customize it a bit. See ActionView::Base for full docs on the 350 # available options. You can add tags/attributes for single uses of #sanitize by passing either the :attributes or :tags options: 351 # 352 # Normal Use 353 # 354 # <%= sanitize @article.body %> 355 # 356 # Custom Use 357 # 358 # <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style) 359 # 360 # Add table tags 361 # 362 # Rails::Initializer.run do |config| 363 # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td' 364 # end 365 # 366 # Remove tags 367 # 368 # Rails::Initializer.run do |config| 369 # config.after_initialize do 370 # ActionView::Base.sanitized_allowed_tags.delete 'div' 371 # end 372 # end 373 # 374 # Change allowed attributes 375 # 376 # Rails::Initializer.run do |config| 377 # config.action_view.sanitized_allowed_attributes = 'id', 'class', 'style' 378 # end 379 # 380 def sanitize(html, options = {}) 381 return html if html.blank? || !html.include?('<') 382 attrs = options.key?(:attributes) ? Set.new(options[:attributes]).merge(sanitized_allowed_attributes) : sanitized_allowed_attributes 383 tags = options.key?(:tags) ? Set.new(options[:tags] ).merge(sanitized_allowed_tags) : sanitized_allowed_tags 384 returning [] do |new_text| 355 385 tokenizer = HTML::Tokenizer.new(html) 356 new_text = "" 357 386 parent = [] 358 387 while token = tokenizer.next 359 388 node = HTML::Node.parse(nil, 0, 0, token, false) 360 389 new_text << case node 361 390 when HTML::Tag 362 if VERBOTEN_TAGS.include?(node.name)363 node.to_s.gsub(/</, "<")391 if node.closing == :close 392 parent.shift 364 393 else 365 if node.closing != :close 366 node.attributes.delete_if { |attr,v| attr =~ VERBOTEN_ATTRS } 367 %w(href src).each do |attr| 368 node.attributes.delete attr if node.attributes[attr] =~ /^javascript:/i 369 end 394 parent.unshift node.name 395 end 396 node.attributes.keys.each do |attr_name| 397 value = node.attributes[attr_name].to_s 398 if !attrs.include?(attr_name) || contains_bad_protocols?(attr_name, value) 399 node.attributes.delete(attr_name) 400 else 401 node.attributes[attr_name] = attr_name == 'style' ? sanitize_css(value) : CGI::escapeHTML(value) 370 402 end 371 node.to_s372 end403 end if node.attributes 404 tags.include?(node.name) ? node : nil 373 405 else 374 node.to_s.gsub(/</, "<")406 sanitized_bad_tags.include?(parent.first) ? nil : node.to_s.gsub(/</, "<") 375 407 end 376 408 end 377 378 html = new_text 379 end 380 381 html 382 end 383 409 end.join 410 end 411 412 # Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute 413 def sanitize_css(style) 414 # disallow urls 415 style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ') 416 417 # gauntlet 418 if style !~ /^([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*$/ || 419 style !~ /^(\s*[-\w]+\s*:\s*[^:;]*(;|$))*$/ 420 return '' 421 end 422 423 returning [] do |clean| 424 style.scan(/([-\w]+)\s*:\s*([^:;]*)/) do |prop,val| 425 if sanitized_allowed_css_properties.include?(prop.downcase) 426 clean << prop + ': ' + val + ';' 427 elsif sanitized_shorthand_css_properties.include?(prop.split('-')[0].downcase) 428 unless val.split().any? do |keyword| 429 !sanitized_allowed_css_keywords.include?(keyword) && 430 keyword !~ /^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$/ 431 end 432 clean << prop + ': ' + val + ';' 433 end 434 end 435 end 436 end.join(' ') 437 end 438 384 439 # Strips all HTML tags from the +html+, including comments. This uses the 385 440 # html-scanner tokenizer and so its HTML parsing ability is limited by … … 408 463 # strip any comments, and if they have a newline at the end (ie. line with 409 464 # only a comment) strip that too 410 text.gsub(/<!--(.*?)-->[\n]?/m, "")465 strip_tags(text.gsub(/<!--(.*?)-->[\n]?/m, "")) # Recurse - handle all dirty nested tags 411 466 else 412 467 html # already plain text … … 575 630 end 576 631 end 632 633 def contains_bad_protocols?(attr_name, value) 634 sanitized_uri_attributes.include?(attr_name) && 635 (value =~ /(^[^\/:]*):|(�*58)|(p)|(%|%)3A/ && !sanitized_allowed_protocols.include?(value.split(sanitized_protocol_separator).first)) 636 end 577 637 end 578 638 end trunk/actionpack/test/template/text_helper_test.rb
r7562 r7589 6 6 include ActionView::Helpers::TagHelper 7 7 include TestingSandbox 8 8 9 9 def setup 10 10 # This simulates the fact that instance variables are reset every time … … 48 48 49 49 def test_strip_links 50 assert_equal "Dont touch me", strip_links("Dont touch me") 50 51 assert_equal "on my mind\nall day long", strip_links("<a href='almost'>on my mind</a>\n<A href='almost'>all day long</A>") 52 assert_equal "0wn3d", strip_links("<a href='http://www.rubyonrails.com/'><a href='http://www.rubyonrails.com/' onlclick='steal()'>0wn3d</a></a>") 53 assert_equal "Magic", strip_links("<a href='http://www.rubyonrails.com/'>Mag<a href='http://www.ruby-lang.org/'>ic") 54 assert_equal "FrrFox", strip_links("<href onlclick='steal()'>FrrFox</a></href>") 55 assert_equal "My mind\nall <b>day</b> long", strip_links("<a href='almost'>My mind</a>\n<A href='almost'>all <b>day</b> long</A>") 56 assert_equal "all <b>day</b> long", strip_links("<<a>a href='hello'>all <b>day</b> long<</A>/a>") 51 57 end 52 58 … … 256 262 257 263 def test_sanitize_form 258 raw = "<form action=\"/foo/bar\" method=\"post\"><input></form>" 259 result = sanitize(raw) 260 assert_equal %(<form action="/foo/bar" method="post"><input></form>), result 264 assert_sanitized "<form action=\"/foo/bar\" method=\"post\"><input></form>", '' 261 265 end 262 266 263 267 def test_sanitize_plaintext 264 268 raw = "<plaintext><span>foo</span></plaintext>" 265 result = sanitize(raw) 266 assert_equal "<plaintext><span>foo</span></plaintext>", result 269 assert_sanitized raw, "<span>foo</span>" 267 270 end 268 271 269 272 def test_sanitize_script 270 raw = "<script language=\"Javascript\">blah blah blah</script>" 271 result = sanitize(raw) 272 assert_equal %{<script language="Javascript">blah blah blah</script>}, result 273 raw = "a b c<script language=\"Javascript\">blah blah blah</script>d e f" 274 assert_sanitized raw, "a b cd e f" 273 275 end 274 276 275 277 def test_sanitize_js_handlers 276 278 raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>} 277 result = sanitize(raw) 278 assert_equal %{onthis="do that" <a name="foo" href="#">hello</a>}, result 279 assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>} 279 280 end 280 281 281 282 def test_sanitize_javascript_href 282 283 raw = %{href="javascript:bang" <a href="javascript:bang" name="hello">foo</a>, <span href="javascript:bang">bar</span>} 283 result = sanitize(raw) 284 assert_equal %{href="javascript:bang" <a name="hello">foo</a>, <span>bar</span>}, result 284 assert_sanitized raw, %{href="javascript:bang" <a name="hello">foo</a>, <span>bar</span>} 285 285 end 286 286 287 287 def test_sanitize_image_src 288 288 raw = %{src="javascript:bang" <img src="javascript:bang" width="5">foo</img>, <span src="javascript:bang">bar</span>} 289 result = sanitize(raw) 290 assert_equal %{src="javascript:bang" <img width="5">foo</img>, <span>bar</span>}, result 291 end 292 289 assert_sanitized raw, %{src="javascript:bang" <img width="5">foo</img>, <span>bar</span>} 290 end 291 292 ActionView::Base.sanitized_allowed_tags.each do |tag_name| 293 define_method "test_should_allow_#{tag_name}_tag" do 294 assert_sanitized "start <#{tag_name} title=\"1\" onclick=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo bar baz</#{tag_name}> end) 295 end 296 end 297 298 def test_should_allow_anchors 299 assert_sanitized %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href="foo"></a>) 300 end 301 302 # RFC 3986, sec 4.2 303 def test_allow_colons_in_path_component 304 assert_sanitized("<a href=\"./this:that\">foo</a>") 305 end 306 307 %w(src width height alt).each do |img_attr| 308 define_method "test_should_allow_image_#{img_attr}_attribute" do 309 assert_sanitized %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />) 310 end 311 end 312 313 def test_should_handle_non_html 314 assert_sanitized 'abc' 315 end 316 317 def test_should_handle_blank_text 318 assert_sanitized nil 319 assert_sanitized '' 320 end 321 322 def test_should_allow_custom_tags 323 text = "<u>foo</u>" 324 assert_equal(text, sanitize(text, :tags => %w(u))) 325 end 326 327 def test_should_allow_custom_tags_with_attributes 328 text = %(<fieldset foo="bar">foo</fieldset>) 329 assert_equal(text, sanitize(text, :attributes => ['foo'])) 330 end 331 332 [%w(img src), %w(a href)].each do |(tag, attr)| 333 define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do 334 assert_sanitized %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>) 335 end 336 end 337 338 def test_should_flag_bad_protocols 339 %w(about chrome data disk hcp help javascript livescript lynxcgi lynxexec ms-help ms-its mhtml mocha opera res resource shell vbscript view-source vnd.ms.radio wysiwyg).each do |proto| 340 assert contains_bad_protocols?('src', "#{proto}://bad") 341 end 342 end 343 344 def test_should_accept_good_protocols 345 sanitized_allowed_protocols.each do |proto| 346 assert !contains_bad_protocols?('src', "#{proto}://good") 347 end 348 end 349 350 def test_should_reject_hex_codes_in_protocol 351 assert contains_bad_protocols?('src', "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29") 352 assert_sanitized %(<a href="%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29">1</a>), "<a>1</a>" 353 end 354 355 def test_should_block_script_tag 356 assert_sanitized %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), "" 357 end 358 359 [%(<IMG SRC="javascript:alert('XSS');">), 360 %(<IMG SRC=javascript:alert('XSS')>), 361 %(<IMG SRC=JaVaScRiPt:alert('XSS')>), 362 %(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">), 363 %(<IMG SRC=javascript:alert("XSS")>), 364 %(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>), 365 %(<IMG SRC=javascript:alert('XSS')>), 366 %(<IMG SRC=javascript:alert('XSS')>), 367 %(<IMG SRC=javascript:alert('XSS')>), 368 %(<IMG SRC="jav\tascript:alert('XSS');">), 369 %(<IMG SRC="jav	ascript:alert('XSS');">), 370 %(<IMG SRC="jav
ascript:alert('XSS');">), 371 %(<IMG SRC="jav
ascript:alert('XSS');">), 372 %(<IMG SRC="  javascript:alert('XSS');">), 373 %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i| 374 define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do 375 assert_sanitized img_hack, "<img>" 376 end 377 end 378 379 def test_should_sanitize_tag_broken_up_by_null 380 assert_sanitized %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), "alert(\"XSS\")" 381 end 382 383 def test_should_sanitize_invalid_script_tag 384 assert_sanitized %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), "" 385 end 386 387 def test_should_sanitize_script_tag_with_multiple_open_brackets 388 assert_sanitized %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "<" 389 assert_sanitized %(<iframe src=http://ha.ckers.org/scriptlet.html\n<a), %(<a) 390 end 391 392 def test_should_sanitize_unclosed_script 393 assert_sanitized %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), "<b>" 394 end 395 396 def test_should_sanitize_half_open_scripts 397 assert_sanitized %(<IMG SRC="javascript:alert('XSS')"), "<img>" 398 end 399 400 def test_should_not_fall_for_ridiculous_hack 401 img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>) 402 assert_sanitized img_hack, "<img>" 403 end 404 405 def test_should_sanitize_attributes 406 assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="'><script>alert()</script>">blah</span>) 407 end 408 409 def test_should_sanitize_illegal_style_properties 410 raw = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;) 411 expected = %(display: block; width: 100%; height: 100%; background-color: black; background-image: ; background-x: center; background-y: center;) 412 assert_equal expected, sanitize_css(raw) 413 end 414 415 def test_should_sanitize_xul_style_attributes 416 raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')) 417 assert_equal '', sanitize_css(raw) 418 end 419 420 def test_should_sanitize_invalid_tag_names 421 assert_sanitized(%(a b c<script/XSS src="http://ha.ckers.org/xss.js"></script>d e f), "a b cd e f") 422 end 423 424 def test_should_sanitize_non_alpha_and_non_digit_characters_in_tags 425 assert_sanitized('<a onclick!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>foo</a>', "<a>foo</a>") 426 end 427 428 def test_should_sanitize_invalid_tag_names_in_single_tags 429 assert_sanitized('<img/src="http://ha.ckers.org/xss.js"/>', "<img />") 430 end 431 432 def test_should_sanitize_img_dynsrc_lowsrc 433 assert_sanitized(%(<img lowsrc="javascript:alert('XSS')" />), "<img />") 434 end 435 436 def test_should_sanitize_div_background_image_unicode_encoded 437 raw = %(background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029) 438 assert_equal '', sanitize_css(raw) 439 end 440 441 def test_should_sanitize_div_style_expression 442 raw = %(width: expression(alert('XSS'));) 443 assert_equal '', sanitize_css(raw) 444 end 445 446 def test_should_sanitize_style_attribute 447 raw = %(<div style="display:block; background:url(http://rubyonrails.com); background-image: url(rubyonrails)">foo</div>) 448 assert_equal %(<div style="display: block; background: ; background-image: ;">foo</div>), sanitize(raw, :attributes => 'style') 449 end 450 451 def test_should_sanitize_img_vbscript 452 assert_sanitized %(<img src='vbscript:msgbox("XSS")' />), '<img />' 453 end 454 455 293 456 def test_cycle_class 294 457 value = Cycle.new("one", 2, "3") … … 375 538 376 539 def test_strip_tags 540 assert_equal("Dont touch me", strip_tags("Dont touch me")) 377 541 assert_equal("This is a test.", strip_tags("<p>This <u>is<u> a <a href='test.html'><strong>test</strong></a>.</p>")) 542 assert_equal("Weirdos", strip_tags("Wei<<a>a onclick='alert(document.cookie);'</a>/>rdos")) 378 543 assert_equal("This is a test.", strip_tags("This is a test.")) 379 544 assert_equal( … … 383 548 [nil, '', ' '].each { |blank| assert_equal blank, strip_tags(blank) } 384 549 end 550 551 def assert_sanitized(text, expected = nil) 552 assert_equal((expected || text), sanitize(text)) 553 end 554 555 # pull in configuration values from ActionView::Base 556 [:sanitized_protocol_separator, :sanitized_protocol_attributes, :sanitized_bad_tags, :sanitized_allowed_tags, :sanitized_allowed_attributes, :sanitized_allowed_protocols, :sanitized_allowed_css_properties, :sanitized_allowed_css_keywords, :sanitized_shorthand_css_properties, :sanitized_uri_attributes].each do |attr| 557 define_method attr do 558 ActionView::Base.send(attr) 559 end 560 end 385 561 end