diff options
author | James Lemieux <jplemieux@google.com> | 2014-05-14 16:39:33 -0700 |
---|---|---|
committer | James Lemieux <jplemieux@google.com> | 2014-05-19 15:44:32 -0700 |
commit | 207a43712406ca88dcc381385ac6a276cb9417e6 (patch) | |
tree | 4414660a76bb16f9f5037b133df9c6f8729a7210 /tests | |
parent | 03728036eefafaac9d05bb917fff3781eb52ebe4 (diff) | |
download | android_packages_apps_UnifiedEmail-207a43712406ca88dcc381385ac6a276cb9417e6.tar.gz android_packages_apps_UnifiedEmail-207a43712406ca88dcc381385ac6a276cb9417e6.tar.bz2 android_packages_apps_UnifiedEmail-207a43712406ca88dcc381385ac6a276cb9417e6.zip |
Sanitize HTML for Android Email and the EML viewer
b/14567151
This check-in introduces the sanitizer class and the necessary build
changes to compile it. A sibling checkin will actually call it.
Change-Id: Ic01e44a5a1c6fcb919880f38a391d8475738886b
Diffstat (limited to 'tests')
-rw-r--r-- | tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java | 537 | ||||
-rw-r--r-- | tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java | 1055 |
2 files changed, 1592 insertions, 0 deletions
diff --git a/tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java b/tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java new file mode 100644 index 000000000..578ce4ae8 --- /dev/null +++ b/tests/src/com/android/mail/utils/AdvancedHtmlSanitizerTest.java @@ -0,0 +1,537 @@ +package com.android.mail.utils; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * These test cases verify the handling of more advanced cross-site scripting attacks. + */ +@SmallTest +public class AdvancedHtmlSanitizerTest extends AndroidTestCase { + public void testSampleEmail() { + sanitize("<html>\n" + + "<head>\n" + + "<title>HTML E-mail</title>\n" + + "<script>\n" + + "alert(\"I am an alert box!\");\n" + + "</script>\n" + + "</head>\n" + + "<body>\n" + + "Body here\n" + + "<br />\n" + + "<a href=\"http://www.google.com\">Link to Google Search!</a>\n" + + "<br />\n" + + "<br />\n" + + "<a onclick=\"alert('surprise!')\" href=\"#\">I am a link!</a>\n" + + "<br />\n" + + "Moar body here\n" + + "</body>\n" + + "</html>" + , + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "<div>\n" + + "Body here\n" + + "<br />\n" + + "<a href=\"http://www.google.com\">Link to Google Search!</a>\n" + + "<br />\n" + + "<br />\n" + + "<a href=\"#\">I am a link!</a>\n" + + "<br />\n" + + "Moar body here\n" + + "</div>\n"); + } + + public void testXSS() { + sanitize("'';!--\"<XSS>=&{()}", "'';!--"=&{()}"); + sanitize("<img src=javascript:alert(String.fromCharCode(88,83,83))>", ""); + sanitize("\\\";alert('XSS');//", "\\";alert('XSS');//"); + sanitize("<br size=\"&{alert('XSS')}\">", "<br />"); + sanitize("<xss style=\"xss:expression(alert('XSS'))\">", ""); + sanitize("<xss style=\"behavior: url(xss.htc);\">", ""); + sanitize("¼script¾alert(¢XSS¢)¼/script¾", "¼script¾alert(¢XSS¢)¼/script¾"); + sanitize("<xml><i><b><img src=\"javas<!-- -->cript:alert('XSS')\"></b></i></xml>", + "<i><b></b></i>"); + sanitize("<xml src=\"xsstest.xml\" id=I></xml>", ""); + sanitize("<!--[if gte IE 4]>\n" + + " <SCRIPT>alert('XSS');</SCRIPT>\n" + + " <![endif]-->", ""); + sanitize("<body>\n" + + "<?xml:namespace prefix=\"t\" ns=\"urn:schemas-microsoft-com:time\">\n" + + "<?import namespace=\"t\" implementation=\"#default#time2\">\n" + + "<t:set attributeName=\"innerHTML\" to=\"XSS<script defer>alert(\"XSS\")" + + "</script>\">\n" + + "</body></html>", + "<div>\n" + + "\n" + + "\n" + + "">\n" + + "</div>"); + } + + /** + * Technically, RFC 2392 doesn't limit where CID urls may appear; they are accepted everywhere. + */ + public void testCIDurls() { + sanitize("<img src=\"http://www.here.com/awesome.png\"/>", + "<img src=\"http://www.here.com/awesome.png\" />"); + sanitize("<img src=\"https://www.here.com/awesome.png\"/>", + "<img src=\"https://www.here.com/awesome.png\" />"); + sanitize("<img src=\"cid:ii_145bda161daf6f9c\"/>", + "<img src=\"cid:ii_145bda161daf6f9c\" />"); + + sanitize("<a href=\"http://www.here.com/awesome.png\"/>", + "<a href=\"http://www.here.com/awesome.png\"></a>"); + sanitize("<a href=\"https://www.here.com/awesome.png\"/>", + "<a href=\"https://www.here.com/awesome.png\"></a>"); + sanitize("<a href=\"cid:ii_145bda161daf6f9c\"/>", + "<a href=\"cid:ii_145bda161daf6f9c\"></a>"); + } + + // todo the stock CssSchema in OWASP does NOT allow the float property; I experiment with adding + // todo it to see how much it beautifies HTML display (the risk seems to be that you can display + // todo content outside the bounds of your div and mislead the user with this technique) + public void testCSS_float() { + sanitize("<div style=\"float:none\"></div>", "<div style=\"float:none\"></div>"); + sanitize("<div style=\"float:left\"></div>", "<div style=\"float:left\"></div>"); + sanitize("<div style=\"float:right\"></div>", "<div style=\"float:right\"></div>"); + sanitize("<div style=\"float:inherit\"></div>", "<div style=\"float:inherit\"></div>"); + sanitize("<div style=\"float:initial\"></div>", "<div></div>"); + sanitize("<div style=\"float:garbage\"></div>", "<div></div>"); + } + + // todo the stock CssSchema in OWASP does NOT allow the display property; I experiment with + // todo adding it to see how much it beautifies HTML display (the risk seems to be that you can + // todo display content outside the bounds of your div and mislead the user with this technique) + public void testCSS_display() { + sanitize("<div style=\"display:inline\"></div>", "<div style=\"display:inline\"></div>"); + sanitize("<div style=\"display:block\"></div>", "<div style=\"display:block\"></div>"); + sanitize("<div style=\"display:flex\"></div>", "<div></div>"); + sanitize("<div style=\"display:inline-block\"></div>", + "<div style=\"display:inline-block\"></div>"); + sanitize("<div style=\"display:inline-flex\"></div>", "<div></div>"); + sanitize("<div style=\"display:inline-table\"></div>", + "<div style=\"display:inline-table\"></div>"); + sanitize("<div style=\"display:list-item\"></div>", + "<div style=\"display:list-item\"></div>"); + sanitize("<div style=\"display:run-in\"></div>", "<div style=\"display:run-in\"></div>"); + sanitize("<div style=\"display:table\"></div>", "<div style=\"display:table\"></div>"); + sanitize("<div style=\"display:table-caption\"></div>", + "<div style=\"display:table-caption\"></div>"); + sanitize("<div style=\"display:table-column-group\"></div>", + "<div style=\"display:table-column-group\"></div>"); + sanitize("<div style=\"display:table-header-group\"></div>", + "<div style=\"display:table-header-group\"></div>"); + sanitize("<div style=\"display:table-footer-group\"></div>", + "<div style=\"display:table-footer-group\"></div>"); + sanitize("<div style=\"display:table-row-group\"></div>", + "<div style=\"display:table-row-group\"></div>"); + sanitize("<div style=\"display:table-cell\"></div>", + "<div style=\"display:table-cell\"></div>"); + sanitize("<div style=\"display:table-column\"></div>", + "<div style=\"display:table-column\"></div>"); + sanitize("<div style=\"display:table-row\"></div>", + "<div style=\"display:table-row\"></div>"); + sanitize("<div style=\"display:none\"></div>", "<div style=\"display:none\"></div>"); + sanitize("<div style=\"display:initial\"></div>", "<div></div>"); + sanitize("<div style=\"display:inherit\"></div>", "<div style=\"display:inherit\"></div>"); + } + + public void testTrimmingUrls() { + // todo Gmail strips the leading space on this href +// sanitize("<a href=\"http://www.google.com \">Send mail</a>", +// "<a href=\"http://www.google.com\">Send mail</a>"); + sanitize("<a href=\" http://www.google.com\">Send mail</a>", "Send mail"); + // todo Gmail strips the trailing space on this href +// sanitize("<a href=\"http://www.google.com \">Send mail</a> ", +// "<a href=\"http://www.google.com\">Send mail</a>"); + sanitize("<a href=\"http://www.google.com \">Send mail</a>", + "<a href=\"http://www.google.com \">Send mail</a>"); + // todo Gmail strips the leading and trailing spaces on this href +// sanitize("<a href=\" http://www.google.com \">Send mail</a> ", +// "<a href=\"http://www.google.com\">Send mail</a>"); + sanitize("<a href=\" http://www.google.com \">Send mail</a>", "Send mail"); + } + + public void testDangerousHtml() { + // body tag is translated to div tag + sanitize("<body dir=\"rtl\" onMouseOVer=\"alert(document.cookie)\">arr</body>", + "<div dir=\"rtl\">arr</div>"); + sanitize("<DIV ONCLICK=alert(document.cookie) style=color:red>arr</DIV>", + "<div style=\"color:red\">arr</div>"); + sanitize("<b style=position:absolute;left:0;top:0>arr</b>", "<b>arr</b>"); + + // mailto: URLs on images are too easy to turn into DOS attacks + sanitize("<img src=\"mailto:\">", ""); + sanitize("<img src=\"mailto:hcnidumolu@google.com\">", ""); + sanitize("<img src=\"mailto:hcnidumolu@google.com\">", ""); + sanitize("<img src=\" mailto:hcnidumolu@google.com\">", ""); + sanitize("<img src=\"mailto:hcnidumolu@google.com\">", ""); + sanitize("<img src=\"m
ailto:hcnidumolu@google.com\">", ""); + // todo Gmail doesn't escape the @ sign; OWASP does by default +// sanitize("<a href=\"mailto:hcnidumolu@google.com\">Send mail </a>", +// "<a href=\"mailto:hcnidumolu@google.com\">Send mail </a>"); + sanitize("<a href=\"mailto:hcnidumolu@google.com\">Send mail </a>", + "<a href=\"mailto:hcnidumolu@google.com\">Send mail </a>"); + } + + public void testSanitizingImgsWithoutSchemes() { + sanitize("<img src=\"//images1-gm-opensocial.googleusercontent.com/gadgets/proxy?" + + "url=http://foo.bar/baz.png&container=gm&gadget=a&rewriteMime=image/*\">", +// "<img src=\"//images1-gm-opensocial.googleusercontent.com/gadgets/proxy?" + +// "url=http://foo.bar/baz.png&container=gm&gadget=" + +// "a&rewriteMime=image/*\">"); // todo Gmail doesn't escape the = signs + "<img src=\"//images1-gm-opensocial.googleusercontent.com/gadgets/proxy?" + + "url=http://foo.bar/baz.png&container=gm&gadget=" + + "a&rewriteMime=image/*\" />"); + } + + public void testAdditionalURISchemes() { + // todo Gmail keeps a destinationless link; OWASP strips the a link completely +// sanitize("<a href=\"foo:bar\" target=\"_blank\">link1</a>", "<a>link1</a>"); + sanitize("<a href=\"foo:bar\" target=\"_blank\">link1</a>", "link1"); + // todo Gmail keeps a destinationless a link; OWASP strips the a link completely +// sanitize("<a href=\"baz:alanbs@google.com\">link2</a>", "<a>link2</a>"); + sanitize("<a href=\"baz:alanbs@google.com\">link2</a>", "link2"); + } + + public void testBackgroundAttribute() { + sanitize("<div background=\"http://www.random.org/png\">stuff</div><div>more stuff</div>", + "<div background=\"http://www.random.org/png\">stuff</div><div>more stuff</div>"); + } + + public void testInputImage() { + sanitize("<input type=\"image\" src=\"http://random.org/png\">", + "<input type=\"image\" src=\"http://random.org/png\" />"); + } + + public void testImplicitInputImage() { + // In HTML 4.01, src attribute has meaning only when type="image" (which + // is not the default), but this happens in real life. + sanitize("<input src=\"http://random.org/png\">", + "<input src=\"http://random.org/png\" />"); + } + + public void testSerialization() { + // N.B. (literal) newlines must not occur in CSS strings. + // todo Gmail leaves this CSS style in place and escapes it; OWASP removes it all +// sanitize("<a href=\"http://www.google.com\" style=\"font-family: 'expression; " + +// "\\a color:red;\\a font-family: completely unsanitized =(;' ;\">asdf</a>", +// "<a href=\"http://www.google.com\" style=\"font-family:'expression; " + +// "\\00000acolor:red;\\00000afont-family: completely unsanitized " + +// "=(;'\">asdf</a>"); + sanitize("<a href=\"http://www.google.com\" style=\"font-family: 'expression; " + + "\\a color:red;\\a font-family: completely unsanitized =(;' ;\">asdf</a>", + "<a href=\"http://www.google.com\">asdf</a>"); + } + + public void testNoJS() { + // todo Gmail leaves this CSS in place and escapes it; OWASP removes it all +// sanitize("<a href=\"http://www.google.com\" style=\"background-image: " + +// "url('javascript:alert(1)')\"></a>", +// "<a href=\"http://www.google.com\" style=\"background-image:" + +// "url('')\"></a>"); + sanitize("<a href=\"http://www.google.com\" style=\"background-image: " + + "url('javascript:alert(1)')\"></a>", + "<a href=\"http://www.google.com\"></a>"); + } + + public void testNoStyleElementByDefault() { + sanitize("<head><style type='text/css'>verboten { color: red; }</style></head>" + + "<body><p>test</p>", + "<div><p>test</p></div>"); + } + + public void testMessageFormation() { + sanitize("<table><tr><td><b>This is a simple message</b></td></tr></table>", + "<table><tr><td><b>This is a simple message</b></td></tr></table>"); + sanitize("<table><tr><td><b>This is a simple message", + "<table><tr><td><b>This is a simple message</b></td></tr></table>"); + sanitize("<table><tr>This is a simple message</b></td></tr></table>", + "<table><tr><td>This is a simple message</td></tr></table>"); + sanitize("This is a simple message</b></td></tr></table>", "This is a simple message"); + } + + public void testViolatingTags() { + sanitize("<html><head><title>html to ruin your site</title>" + + "<meta http-equiv=\"refresh\" content=\"5\" />" + + "<link rel=\"stylesheet\" type=\"text/css\" href=\"some site\"/>" + + "<style type=\"text/css\"> h1 {color: red}</style>" + + "</head><body><script>some script to run</script>" + + "<noscript>Please enable Javascript and reload this page." + + "Good things abound!</noscript>" + + "<noframes>This page requires frames!</noframes>" + + "<frameset cols = \"25%, 25%,*\">" + + "<frame src=\"site1.htm\" />" + + "<frame src=\"site2.htm\" />" + + "<frame src=\"site3.htm\" /> " + + "</frameset>" + + "<table><tr><td>" + + "Execute this <applet code=\"some evil site\"></td>" + + "</tr></table></body></html>" + , + "<div>" + + "<table><tr><td>" + + "Execute this </td>" + + "</tr></table></div>" + ); + + sanitize("Include this:<br/>" + + "<object classid=\"clsid:FOOBAR\" id=\"Slider1\"" + + "declare=\"declare\">" + + "<param name=\"some param\" value=\"1\" />" + + "</object><br/>" + + "<form method=\"POST\" action=\"http://www.somesite.com\"" + + "onsubmit=\"run some script\">" + + "<input type=\"text\" onclick=\"run some script\" id=\"input\"/>" + + "<input type=\"submit\" onfocus=\"run some script\" value=\"submit\"/>" + + "</form>" + , + "Include this:<br />" + + "<br />" + + "<form method=\"POST\" action=\"http://www.somesite.com\">" + + "<input type=\"text\" />" + + "<input type=\"submit\" value=\"submit\" />" + + "</form>" + ); + } + + public void testLinks() { + sanitize("<a href=\"http://www.somesite.com\" target=\"_self\" " + + "onclick=\"run some script\" onmouseover=\"run some script\">" + + "click here</a>" + + "<a href=\"javascript:run some script\">here</a>" + + "<a href=\"someinternalpage.htm\">or here</a>" + , + "<a href=\"http://www.somesite.com\">" + + "click here</a>" + + "here" + + "<a href=\"someinternalpage.htm\">or here</a>" + ); + } + + public void testExternalLinks() { + sanitize("This is a test <a href=http://google.com>here</a> " + + "<img src=\"http://google.com/bogus.jpg\">" + + "<img src=\"//google.com/bogus2.jpg\">" + + "<img src=\"google.com/bogus3.jpg\">" + + "<script>Hello</script> " + + "<frameset><frame src=foo name=onlyFrame>hey</frame></frameset>" + , + "This is a test <a href=\"http://google.com\">here</a> " + + "<img src=\"http://google.com/bogus.jpg\" />" + + "<img src=\"//google.com/bogus2.jpg\" />" + + "<img src=\"google.com/bogus3.jpg\" /> " + ); + } + + public void testNewHtmlWhitelist() { + sanitize("<a href=http://google.com/boguslink>link</a>" + + "<b>BOLD</b>" + + "<i>italics</i>" + + "<u>underlined</u>" + + "<br/>break<br>break" + + "<font size=+1>Big_font_gone</font>" + , + "<a href=\"http://google.com/boguslink\">link</a>" + + "<b>BOLD</b>" + + "<i>italics</i>" + + "<u>underlined</u>" + + "<br />break<br />break" + + "<font size=\"+1\">Big_font_gone</font>" + ); + } + + public void testRemoveBackticksInAttributes() { + // IE treats backticks as quotes when re-serializing, but not when parsing + sanitize("<img alt=\"``onload=alert(1)\">", + "<img alt=\"``onload=alert(1) \" />"); + sanitize("<img alt=\"'``onload=alert(1)'\">", + "<img alt=\"'``onload=alert(1)' \" />"); + sanitize("<img alt=``onload=alert(1)\">", "<img alt=\"``onload=alert(1) \" />"); + + // Make sure we're not fooled by escaped backticks + sanitize("<img alt=\"``onload=alert(1)\">", + "<img alt=\"``onload=alert(1) \" />"); + sanitize("<img alt=\"``onload=alert(1)\">", + "<img alt=\"``onload=alert(1) \" />"); + + // Misc. dangerous cases: + sanitize("<img alt=`x`onload=alert(1)>", "<img alt=\"`x`onload=alert(1) \" />"); + sanitize("<img alt=foo`x`onload=alert(1)>", + "<img alt=\"foo`x`onload=alert(1) \" />"); + sanitize("<img alt=\"`whatever\">Hello world ` onload=alert(1) <br>", + "<img alt=\"`whatever \" />Hello world ` onload=alert(1) <br />"); + + // The tokenizer doesn't see these as entities because they lack a trailing semicolon, so it + // escapes the leading ampersands. + sanitize("<img alt=\"``onload=alert(1)\">", + "<img alt=\"`&#x000060onload=alert(1) \" />"); + + // Here there are no actual backticks, though there would be if we (or IE) did repeated + // unescaping. + sanitize("<img alt=\"&#x000060&#x000060onload=alert(2)\">", + "<img alt=\"&#x000060&#x000060onload=alert(2)\" />"); + sanitize("<img alt=\"&amp;#x000060&amp;#x000060onload=alert(2)\">", + "<img alt=\"&amp;#x000060&amp;#x000060onload=alert(2)\" />"); + } + + public void testMakeSafeStyle() { + sanitize("<div style=\"color:red\"></div>", "<div style=\"color:red\"></div>"); + sanitize("<div style=\"color:r\\ne\\t d d\\r\\n\"></div>", "<div></div>"); + sanitize("<div style=\"font-size:13.5pt; color:#804000 \"></div>", + "<div style=\"font-size:13.5pt;color:#804000\"></div>"); + sanitize("<div style=\"color:red;color\"></div>", "<div style=\"color:red\"></div>"); + sanitize("<div style=\"color:red;color:a:b\"></div>", "<div style=\"color:red\"></div>"); + sanitize("<div style=\"color:url(foo)\"></div>", "<div></div>"); + sanitize("<div style=\"color:white; list-style:url(foo.gif);\"></div>", + "<div style=\"color:white\"></div>"); + sanitize("<div style=\"color:rgb(255, 0, 0)\"></div>", + "<div style=\"color:rgb( 255 , 0 , 0 )\"></div>"); + sanitize("<div style=\"background-color:rgb(80%,92%,18%)\"></div>", + "<div style=\"background-color:rgb( 80% , 92% , 18% )\"></div>"); + sanitize("<div style=\"border-left:1px rgb(0,255,0) solid\"></div>", + "<div style=\"border-left:1px rgb( 0 , 255 , 0 ) solid\"></div>"); + sanitize("<div style=\"background:rgb(0,255,0) url(foo) no-repeat top\"></div>", + "<div style=\"background:rgb( 0 , 255 , 0 ) no-repeat top\"></div>"); + sanitize("<div style=\"display:none; border-color: #ffeeff \"></div>", + "<div style=\"display:none;border-color:#ffeeff\"></div>"); + + // check for CSS3 border-radius + sanitize("<div style=\"border-radius:10px\"></div>", + "<div style=\"border-radius:10px\"></div>"); + sanitize("<div style=\"border-bottom-left-radius:10px\"></div>", + "<div style=\"border-bottom-left-radius:10px\"></div>"); + sanitize("<div style=\"border-bottom-right-radius:10px\"></div>", + "<div style=\"border-bottom-right-radius:10px\"></div>"); + sanitize("<div style=\"border-top-left-radius:10px\"></div>", + "<div style=\"border-top-left-radius:10px\"></div>"); + sanitize("<div style=\"border-top-right-radius:10px\"></div>", + "<div style=\"border-top-right-radius:10px\"></div>"); + + // allow positive margins + sanitize("<div style=\"margin:10 0 10 0\"></div>", + "<div style=\"margin:10 0 10 0\"></div>"); + sanitize("<div style=\"margin-left:40px\"></div>", + "<div style=\"margin-left:40px\"></div>"); + + // negative margin would allow it to slip out of the box + sanitize("<div style=\"margin-left:-10\"></div>", "<div></div>"); + + // allow positive text-ident + sanitize("<div style=\"text-indent:10\"></div>", "<div style=\"text-indent:10\"></div>"); + sanitize("<div style=\"text-indent:0\"></div>", "<div style=\"text-indent:0\"></div>"); + + // todo Gmail disallows negative text-indents; OWASP is fine with them + // negative text-indent would allow it to slip out of the box +// sanitize("<div style=\"text-indent:-10\"></div>", "<div></div>"); + sanitize("<div style=\"text-indent:-10\"></div>", "<div style=\"text-indent:-10\"></div>"); + } + + public void testMakeSafeStyleWithQuotedStrings() { + sanitize("<div style=\"font-family:'courier new',monospace;font-size:x-small\"></div>", + "<div style=\"font-family:'courier new' , monospace;font-size:x-small\">" + + "</div>"); + sanitize("<div style=\"font-family:\"courier new\",monospace\"></div>", "<div></div>"); + sanitize("<div style=\"font-family:''\"></div>", "<div></div>"); + sanitize("<div style=\"font-family:a,''\"></div>", + "<div style=\"font-family:'a' ,\"></div>"); + sanitize("<div style=\"font-family:'',a,\"\",b\"></div>", + "<div style=\"font-family:, 'a' ,\"></div>"); + + sanitize("<div style=\"font-family:'\"></div>", "<div></div>"); + sanitize("<div style=\"font-family: 'courier new\",monospace;'\"></div>", "<div></div>"); + sanitize("<div style=\"font-family: \"courier new',monospace;\"></div>", "<div></div>"); + } + + public void testSeriouslyNoBackgroundImages() { + sanitize("<div style=\"background:url('http://www.here.com/awesome.png')\"></div>", + "<div></div>"); + sanitize("<div style=\"background-image:url('http://www.here.com/awesome.png')\"></div>", + "<div></div>"); + + sanitize("<div style=\"background:url('javascript:evil()')\"></div>", "<div></div>"); + sanitize("<div style=\"background-image:url('javascript:evil()')\"></div>", "<div></div>"); + } + + public void testExpression() { + sanitize("<div style=\"width: expression(alert(1))\"></div>", "<div></div>"); + } + + public void testStrayUrlConsideredHarmful() { + sanitize("<div style=\"float:url(\"></div>", "<div></div>"); + sanitize("<div style=\"float:\\075\\0072\\006C\\0028\"></div>", "<div></div>"); + } + + public void testObjectionableFunctions() { + sanitize("<div style=\"ex\\pression(123)\"></div>", "<div></div>"); + sanitize("<div style=\"_expression(123)\"></div>", "<div></div>"); + sanitize("<div style=\"expression(123)\"></div>", "<div></div>"); + sanitize("<div style=\"funkyFunction(123)\"></div>", "<div></div>"); + + sanitize("<div style=\"color:expression(alert('xss'))\"></div>", "<div></div>"); + sanitize("<div style=\"color:expression(alert\\000028\\000027xss\\000027\\000029)\"></div>", + "<div></div>"); + sanitize("<div style=\"color:expression\\000028alert\\000028\\000027xss\\000027" + + "\\000029\\000029\"></div>", "<div></div>"); + sanitize("<div style=\"color:expressio\\00006E\\000028alert\\000028\\000027xss\\000027" + + "\\000029\\000029\"\"></div>", "<div></div>"); + sanitize("<div style=\"color:expression\\(alert\\)\"></div>", "<div></div>"); + } + + public void testAbsolutePositionBanned() { + sanitize("<div style=\"position: absolute\"></div>", "<div></div>"); + } + + public void testNoTextShadow() { + // todo Gmail disallows this text-shadow; OWASP is fine with it +// sanitize("<div style=\"text-shadow: red -50px -100px 0px\"></div>", "<div></div>"); + sanitize("<div style=\"text-shadow: red -50px -100px 0px\"></div>", + "<div style=\"text-shadow:red -50px -100px 0px\"></div>"); + } + + public void testToStyle() { + sanitize("<div style=\"color:red\"></div>", "<div style=\"color:red\"></div>"); + sanitize("<div style=\"color: red\"></div>", "<div style=\"color:red\"></div>"); + sanitize("<div style=\"color :red\"></div>", "<div style=\"color:red\"></div>"); + sanitize("<div style=\"color :red; font-size:13.5pt;\"></div>", + "<div style=\"color:red;font-size:13.5pt\"></div>"); + sanitize("<div style=\"content:'\"'\"></div>", "<div></div>"); + } + + public void testNoColorStrings() { + sanitize("<div style=\"color: 'red';\"></div>", "<div></div>"); + } + + public void testTolerateMalformedBorder() { + sanitize("<div style=\"border-left-: solid thin red\"></div>", "<div></div>"); + } + + public void testRgba() { + sanitize("<div style=\"color:rgba(255, 0, 0, 0.5)\"></div>", + "<div style=\"color:rgba( 255 , 0 , 0 , 0.5 )\"></div>"); + } + + public void testFontStyle() { + // todo Gmail accepts !important while OWASP discards it; this is only beauty, not security +// sanitize("<div style=\"font-style:normal!important\"></div>", +// "<div style=\"font-style:normal!important\"></div>"); + sanitize("<div style=\"font-style:normal!important\"></div>", + "<div style=\"font-style:normal\"></div>"); + // todo Gmail accepts !important while OWASP discards it; this is only beauty, not security +// sanitize("<div style=\"font-style:oblique !important\"></div>", +// "<div style=\"font-style:oblique!important\"></div>"); + sanitize("<div style=\"font-style:oblique !important\"></div>", + "<div style=\"font-style:oblique\"></div>"); + sanitize("<div style=\"font-style:italic\"></div>", + "<div style=\"font-style:italic\"></div>"); + } + + private void sanitize(String dirtyHTML, String expectedHTML) { + final String cleansedHTML = HtmlSanitizer.sanitizeHtml(dirtyHTML); + assertEquals(expectedHTML, cleansedHTML); + } +} diff --git a/tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java b/tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java new file mode 100644 index 000000000..d0e23abe7 --- /dev/null +++ b/tests/src/com/android/mail/utils/BasicHtmlSanitizerTest.java @@ -0,0 +1,1055 @@ +package com.android.mail.utils; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * These test cases verify that each white listed element and attribute is accepted by the sanitizer + * and everything else is correctly discarded. + */ +@SmallTest +public class BasicHtmlSanitizerTest extends AndroidTestCase { + public void testAttributeDir() { + sanitize("<div dir=\"ltr\">something</div>", "<div dir=\"ltr\">something</div>"); + sanitize("<div dir=\"rtl\">something</div>", "<div dir=\"rtl\">something</div>"); + sanitize("<div dir=\"LTR\">something</div>", "<div dir=\"ltr\">something</div>"); + sanitize("<div dir=\"RTL\">something</div>", "<div dir=\"rtl\">something</div>"); + sanitize("<div dir=\"blah\">something</div>", "<div>something</div>"); + } + + public void testA() { + // allowed attributes + sanitize("<a coords=\"something\"></a>", "<a coords=\"something\"></a>"); + sanitize("<a href=\"http://www.here.com\"></a>", "<a href=\"http://www.here.com\"></a>"); + sanitize("<a name=\"something\"></a>", "<a name=\"something\"></a>"); + sanitize("<a shape=\"something\"></a>", "<a shape=\"something\"></a>"); + + // disallowed attributes (all links should launch a browser so we don't need these) + sanitize("<a charset=\"something\"></a>", ""); + sanitize("<a datafld=\"something\"></a>", ""); + sanitize("<a datasrc=\"something\"></a>", ""); + sanitize("<a download=\"something\"></a>", ""); + sanitize("<a href=\"javascript:badness()\"></a>", ""); + sanitize("<a hreflang=\"something\"></a>", ""); + sanitize("<a media=\"something\"></a>", ""); + sanitize("<a methods=\"something\"></a>", ""); + sanitize("<a ping=\"something\"></a>", ""); + sanitize("<a rel=\"something\"></a>", ""); + sanitize("<a rev=\"something\"></a>", ""); + sanitize("<a target=\"_top\"></a>", ""); + sanitize("<a type=\"_top\"></a>", ""); + sanitize("<a urn=\"_top\"></a>", ""); + sanitize("<a onmouseout=\"alert(document.cookie)\">xxs link</a>", "xxs link"); + sanitize("<a onmouseover=\"alert(document.cookie)\">xxs link</a>", "xxs link"); + sanitize("<a onmouseover=alert(document.cookie)>xxs link</a>", "xxs link"); + sanitize("exp/*<a style='no\\xss:noxss(\"*//*\");\n" + + "xss:ex/*XSS*//*/*/pression(alert(\"XSS\"))'>", "exp/*"); + } + + public void testAbbr() { + sanitize("<abbr title=\"United Kingdom\">UK</abbr>", + "<abbr title=\"United Kingdom\">UK</abbr>"); + } + + public void testAcronym() { + sanitize("<acronym title=\"World Wide Web\">WWW</acronym>", + "<acronym title=\"World Wide Web\">WWW</acronym>"); + } + + public void testAddress() { + sanitize("<address>something</address>", "<address>something</address>"); + } + + public void testApplet() { + // todo Gmail would also strip "malicious applet" as well... is this a problem? + sanitize("<applet>malicious applet</applet>", "malicious applet"); + } + + public void testArea() { + // allowed attributes + sanitize("<area alt=\"something\"/>", "<area alt=\"something\" />"); + sanitize("<area coords=\"something\"/>", "<area coords=\"something\" />"); + sanitize("<area href=\"http://www.here.com\"/>", "<area href=\"http://www.here.com\" />"); + sanitize("<area name=\"something\"/>", "<area name=\"something\" />"); + sanitize("<area nohref />", "<area nohref=\"nohref\" />"); + sanitize("<area shape=\"something\"/>", "<area shape=\"something\" />"); + + // disallowed attributes (all links launch a browser so we don't need these attributes) + sanitize("<area accessKey=\"A\"/>", "<area />"); + sanitize("<area download=\"something\"/>", "<area />"); + sanitize("<area href=\"javascript:badness()\"/>", "<area />"); + sanitize("<area hreflang=\"something\"/>", "<area />"); + sanitize("<area media=\"something\"/>", "<area />"); + sanitize("<area rel=\"something\"/>", "<area />"); + sanitize("<area target=\"something\"/>", "<area />"); + sanitize("<area tabindex=\"something\"/>", "<area />"); + sanitize("<area type=\"something\"/>", "<area />"); + } + + public void testArticle() { + sanitize("<article></article>", "<article></article>"); + } + + public void testAside() { + sanitize("<aside></aside>", "<aside></aside>"); + } + + public void testAudio() { + sanitize("<audio>not supported</audio>", "not supported"); + } + + public void testB() { + sanitize("<b>something</b>", "<b>something</b>"); + } + + public void testBase() { + // allowed attributes + sanitize("<base href=\"http://www.example.com/\">", + "<base href=\"http://www.example.com/\" />"); + + // disallowed attributes + sanitize("<base target=\"_blank\">", "<base />"); + sanitize("<base href=\"javascript:badness()\">", "<base />"); + sanitize("<base href=\"javascript:alert('XSS');//\">", "<base />"); + } + + public void testBasefont() { + sanitize("<basefont color=\"something\"/>", ""); + sanitize("<basefont face=\"something\"/>", ""); + sanitize("<basefont size=\"something\"/>", ""); + } + + public void testBdi() { + sanitize("<bdi>something</bdi>", "<bdi>something</bdi>"); + sanitize("<bdi dir=\"ltr\">something</bdi>", "<bdi dir=\"ltr\">something</bdi>"); + } + + public void testBdo() { + sanitize("<bdo>something</bdo>", "<bdo>something</bdo>"); + sanitize("<bdo dir=\"ltr\">something</bdo>", "<bdo dir=\"ltr\">something</bdo>"); + } + + public void testBgsound() { + sanitize("<bgsound src=\"sound1.mid\">", ""); + sanitize("<bgsound src=\"javascript:alert('XSS');\">", ""); + } + + public void testBig() { + sanitize("<big>something</big>", "<big>something</big>"); + } + + public void testBlink() { + sanitize("<blink>something</blink>", "something"); + } + + public void testBlockquote() { + sanitize("<blockquote>something</blockquote>", "<blockquote>something</blockquote>"); + sanitize("<blockquote cite=\"http://www.here.com\">something</blockquote>", + "<blockquote cite=\"http://www.here.com\">something</blockquote>"); + sanitize("<blockquote cite=\"javascript:badness()\">something</blockquote>", + "<blockquote>something</blockquote>"); + + sanitize("<blockquote style=\"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;" + + "padding-left:1ex\">", + "<blockquote style=\"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;" + + "padding-left:1ex\"></blockquote>"); + } + + /** + * The body tag will be supplied by code that wraps this email with other formatting logic. + * So, any body tags appearing within the email are translated to div tags. + */ + public void testBody() { + sanitize("<body alink=\"something\"></body>", "<div></div>"); + sanitize("<body background=\"something\"></body>", "<div></div>"); + sanitize("<body bgcolor=\"something\"></body>", "<div></div>"); + sanitize("<body link=\"something\"></body>", "<div></div>"); + sanitize("<body text=\"something\"></body>", "<div></div>"); + sanitize("<body vlink=\"something\"></body>", "<div></div>"); + + // take extra care to ensure that these scripting callbacks don't survive + sanitize("<body onafterprint=\"something\"></body>", "<div></div>"); + sanitize("<body onbeforeprint=\"something\"></body>", "<div></div>"); + sanitize("<body onbeforeunload=\"something\"></body>", "<div></div>"); + sanitize("<body onblur=\"something\"></body>", "<div></div>"); + sanitize("<body onerror=\"something\"></body>", "<div></div>"); + sanitize("<body onfocus=\"something\"></body>", "<div></div>"); + sanitize("<body onhashchange=\"something\"></body>", "<div></div>"); + sanitize("<body onload=\"something\"></body>", "<div></div>"); + sanitize("<body onmessage=\"something\"></body>", "<div></div>"); + sanitize("<body onoffline=\"something\"></body>", "<div></div>"); + sanitize("<body ononline=\"something\"></body>", "<div></div>"); + sanitize("<body onpopstate=\"something\"></body>", "<div></div>"); + sanitize("<body onredo=\"something\"></body>", "<div></div>"); + sanitize("<body onresize=\"something\"></body>", "<div></div>"); + sanitize("<body onstorage=\"something\"></body>", "<div></div>"); + sanitize("<body onundo=\"something\"></body>", "<div></div>"); + sanitize("<body onunload=\"something\"></body>", "<div></div>"); + sanitize("<body onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>", "<div></div>"); + sanitize("<body background=\"javascript:alert('XSS')\">", "<div></div>"); + sanitize("<body onload=alert('XSS')>", "<div></div>"); + sanitize("<body onload =alert('XSS')>", "<div></div>"); + } + + public void testBr() { + sanitize("something<br>something", "something<br />something"); + sanitize("something<br clear=\"all\">something", "something<br clear=\"all\" />something"); + } + + public void testButton() { + sanitize("<button>Click Me!</button>", "<button>Click Me!</button>"); + sanitize("<button autofocus=\"true\">Click Me!</button>", + "<button autofocus=\"true\">Click Me!</button>"); + sanitize("<button disabled=\"true\">Click Me!</button>", + "<button disabled=\"true\">Click Me!</button>"); + sanitize("<button formenctype=\"text/plain\">Click Me!</button>", + "<button formenctype=\"text/plain\">Click Me!</button>"); + sanitize("<button formmethod=\"post\">Click Me!</button>", + "<button formmethod=\"post\">Click Me!</button>"); + sanitize("<button formnovalidate=\"formnovalidate\">Click Me!</button>", + "<button formnovalidate=\"formnovalidate\">Click Me!</button>"); + sanitize("<button formtarget=\"_top\">Click Me!</button>", + "<button formtarget=\"_top\">Click Me!</button>"); + sanitize("<button name=\"something\">Click Me!</button>", + "<button name=\"something\">Click Me!</button>"); + sanitize("<button type=\"button\">Click Me!</button>", + "<button type=\"button\">Click Me!</button>"); + sanitize("<button value=\"something\">Click Me!</button>", + "<button value=\"something\">Click Me!</button>"); + sanitize("<button formaction=\"http://www.overhere.com/\">Click Me!</button>", + "<button formaction=\"http://www.overhere.com/\">Click Me!</button>"); + + sanitize("<button formaction=\"javascript:badness()\">Click Me!</button>", + "<button>Click Me!</button>"); + } + + public void testCanvas() { + sanitize("<canvas></canvas>", "<canvas></canvas>"); + sanitize("<canvas width=\"500\"></canvas>", "<canvas width=\"500\"></canvas>"); + sanitize("<canvas height=\"500\"></canvas>", "<canvas height=\"500\"></canvas>"); + } + + public void testCaption() { + sanitize("<caption>something</caption>", "<caption>something</caption>"); + sanitize("<caption align=\"left\">something</caption>", + "<caption align=\"left\">something</caption>"); + } + + public void testCenter() { + sanitize("<center>something</center>", "<center>something</center>"); + } + + public void testCite() { + sanitize("<cite>something</cite>", "<cite>something</cite>"); + } + + public void testCode() { + sanitize("<code>something</code>", "<code>something</code>"); + } + + public void testCol() { + sanitize("<col>", "<col />"); + sanitize("<col align=\"left\">", "<col align=\"left\" />"); + sanitize("<col bgcolor=\"something\">", "<col bgcolor=\"something\" />"); + sanitize("<col char=\"something\">", "<col char=\"something\" />"); + sanitize("<col charoff=\"something\">", "<col charoff=\"something\" />"); + sanitize("<col span=\"something\">", "<col span=\"something\" />"); + sanitize("<col valign=\"something\">", "<col valign=\"something\" />"); + sanitize("<col width=\"something\">", "<col width=\"something\" />"); + } + + public void testColgroup() { + sanitize("<colgroup></colgroup>", "<colgroup></colgroup>"); + sanitize("<colgroup align=\"left\"></colgroup>", "<colgroup align=\"left\"></colgroup>"); + sanitize("<colgroup char=\"something\"></colgroup>", + "<colgroup char=\"something\"></colgroup>"); + sanitize("<colgroup charoff=\"something\"></colgroup>", + "<colgroup charoff=\"something\"></colgroup>"); + sanitize("<colgroup span=\"something\"></colgroup>", + "<colgroup span=\"something\"></colgroup>"); + sanitize("<colgroup valign=\"something\"></colgroup>", + "<colgroup valign=\"something\"></colgroup>"); + sanitize("<colgroup width=\"something\"></colgroup>", + "<colgroup width=\"something\"></colgroup>"); + } + + public void testDatalist() { + sanitize("<datalist></datalist>", "<datalist></datalist>"); + } + + public void testDd() { + sanitize("<dd>something</dd>", "<dd>something</dd>"); + } + + public void testDel() { + sanitize("<del>something</del>", "<del>something</del>"); + sanitize("<del cite=\"javascript:badness();\">something</del>", "<del>something</del>"); + sanitize("<del cite=\"http://www.reason.com/\">something</del>", + "<del cite=\"http://www.reason.com/\">something</del>"); + sanitize("<del datetime=\"something\">something</del>", + "<del datetime=\"something\">something</del>"); + } + + public void testDetails() { + sanitize("<details>something</details>", "<details>something</details>"); + } + + public void testDfn() { + sanitize("<dfn>something</dfn>", "<dfn>something</dfn>"); + } + + public void testDialog() { + sanitize("<dialog open>This is an open dialog window</dialog>", + "This is an open dialog window"); + } + + public void testDir() { + sanitize("<dir><li>something</li></dir>", "<dir><li>something</li></dir>"); + sanitize("<dir compact=\"compact\"><li>something</li></dir>", + "<dir compact=\"compact\"><li>something</li></dir>"); + } + + public void testDiv() { + sanitize("<div></div>", "<div></div>"); + sanitize("<div align=\"left\"></div>", "<div align=\"left\"></div>"); + sanitize("<div background=\"http://www.random.com/mypng.gif\"></div>", + "<div background=\"http://www.random.com/mypng.gif\"></div>"); + + sanitize("<div background=\"javascript:badness();\"></div>", "<div></div>"); + sanitize("<div style=\"width: expression(alert('XSS'));\">", "<div></div>"); + sanitize("<div style=\"background-image: url(javascript:alert('XSS'))\">", "<div></div>"); + sanitize("<div style=\"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\">", "<div></div>"); + sanitize("<div style=\"background-image: url(javascript:alert('XSS'))\">", + "<div></div>"); + } + + public void testDl() { + sanitize("<dl></dl>", "<dl></dl>"); + } + + public void testDt() { + sanitize("<dt></dt>", "<dt></dt>"); + } + + public void testEm() { + sanitize("<em>something</em>", "<em>something</em>"); + } + + public void testEmbed() { + sanitize("<embed src=\"helloworld.swf\">", ""); + } + + public void testFieldset() { + sanitize("<fieldset>something</fieldset>", "<fieldset>something</fieldset>"); + sanitize("<fieldset disabled=\"true\">something</fieldset>", + "<fieldset disabled=\"true\">something</fieldset>"); + sanitize("<fieldset form=\"formId\">something</fieldset>", + "<fieldset form=\"formId\">something</fieldset>"); + sanitize("<fieldset name=\"something\">something</fieldset>", + "<fieldset name=\"something\">something</fieldset>"); + } + + public void testFigcaption() { + sanitize("<figcaption>Fig1. something</figcaption>", + "<figcaption>Fig1. something</figcaption>"); + } + + public void testFigure() { + sanitize("<figure>something</figure>", "<figure>something</figure>"); + } + + public void testFont() { + sanitize("<font>something</font>", "something"); + sanitize("<font size=\"3\">something</font>", "<font size=\"3\">something</font>"); + sanitize("<font face=\"verdana\">something</font>", + "<font face=\"verdana\">something</font>"); + sanitize("<font color=\"red\">something</font>", "<font color=\"red\">something</font>"); + } + + public void testFooter() { + sanitize("<footer>something</footer>", "<footer>something</footer>"); + } + + public void testForm() { + sanitize("<form></form>", "<form></form>"); + sanitize("<form accept=\"something\"></form>", "<form accept=\"something\"></form>"); + sanitize("<form accept-charset=\"something\"></form>", + "<form accept-charset=\"something\"></form>"); + sanitize("<form autocomplete=\"on\"></form>", "<form autocomplete=\"on\"></form>"); + sanitize("<form enctype=\"text/plain\"></form>", "<form enctype=\"text/plain\"></form>"); + sanitize("<form method=\"get\"></form>", "<form method=\"get\"></form>"); + sanitize("<form name=\"something\"></form>", "<form name=\"something\"></form>"); + sanitize("<form novalidate=\"novalidate\"></form>", + "<form novalidate=\"novalidate\"></form>"); + sanitize("<form target=\"_top\"></form>", "<form target=\"_top\"></form>"); + sanitize("<form action=\"http://www.overhere.com/\"></form>", + "<form action=\"http://www.overhere.com/\"></form>"); + + sanitize("<form action=\"javascript:badness()\"></form>", "<form></form>"); + sanitize("<form onsubmit=\"javascript:badness()\"></form>", "<form></form>"); + sanitize("<form onreset=\"javascript:badness()\"></form>", "<form></form>"); + } + + public void testFrame() { + sanitize("<frame src=\"frame_a.htm\">", ""); + } + + public void testFrameset() { + sanitize("<frameset cols=\"25%,*,25%\"></frameset>", ""); + sanitize("<frameset><frame src=\"javascript:alert('XSS');\"></frameset>", ""); + } + + public void testHead() { + sanitize("<head></head>", ""); + sanitize("<head profile=\"http://www.overhere.com/\"></head>", ""); + sanitize("<head profile=\"javascript:badness()\"></head>", ""); + } + + public void testHeader() { + sanitize("<header></header>", "<header></header>"); + } + + public void testH1() { + sanitize("<h1>something</h1>", "<h1>something</h1>"); + sanitize("<h1 align=\"left\">something</h1>", "<h1 align=\"left\">something</h1>"); + } + + public void testH2() { + sanitize("<h2>something</h2>", "<h2>something</h2>"); + sanitize("<h2 align=\"left\">something</h2>", "<h2 align=\"left\">something</h2>"); + } + + public void testH3() { + sanitize("<h3>something</h3>", "<h3>something</h3>"); + sanitize("<h3 align=\"left\">something</h3>", "<h3 align=\"left\">something</h3>"); + } + + public void testH4() { + sanitize("<h4>something</h4>", "<h4>something</h4>"); + sanitize("<h4 align=\"left\">something</h4>", "<h4 align=\"left\">something</h4>"); + } + + public void testH5() { + sanitize("<h5>something</h5>", "<h5>something</h5>"); + sanitize("<h5 align=\"left\">something</h5>", "<h5 align=\"left\">something</h5>"); + } + + public void testH6() { + sanitize("<h6>something</h6>", "<h6>something</h6>"); + sanitize("<h6 align=\"left\">something</h6>", "<h6 align=\"left\">something</h6>"); + } + + public void testHr() { + sanitize("<hr/>", "<hr />"); + sanitize("<hr align=\"left\"/>", "<hr align=\"left\" />"); + sanitize("<hr noshade=\"noshade\"/>", "<hr noshade=\"noshade\" />"); + sanitize("<hr size=\"11\"/>", "<hr size=\"11\" />"); + sanitize("<hr width=\"666\"/>", "<hr width=\"666\" />"); + } + + public void testHtml() { + sanitize("<html></html>", ""); + sanitize("<html xmlns=\"http://www.w3.org/1999/xhtml\"></html>", ""); + sanitize("<html manifest=\"http://www.overhere.com/\"></html>", ""); + sanitize("<html manifest=\"javascript:badness()\"></html>", ""); + } + + public void testI() { + sanitize("<i></i>", "<i></i>"); + } + + public void testIframe() { + sanitize("<iframe src=\"http://www.w3schools.com\"></iframe>", ""); + sanitize("<iframe src=http://ha.ckers.org/scriptlet.html <", ""); + sanitize("<iframe src=\"javascript:alert('XSS');\"></iframe>", ""); + sanitize("<iframe src=# onmouseover=\"alert(document.cookie)\"></iframe>", ""); + } + + public void testIsindex() { + sanitize("<isindex prompt=\"Search Document... \"/>", ""); + } + + public void testImg() { + sanitize("<img/>", ""); + sanitize("<img align=\"left\"/>", "<img align=\"left\" />"); + sanitize("<img alt=\"something\"/>", "<img alt=\"something\" />"); + sanitize("<img border=\"22\"/>", "<img border=\"22\" />"); + sanitize("<img crossorigin=\"anonymous \"/>", "<img crossorigin=\"anonymous \" />"); + sanitize("<img height=\"22\"/>", "<img height=\"22\" />"); + sanitize("<img hspace=\"22\"/>", "<img hspace=\"22\" />"); + sanitize("<img ismap=\"ismap\"/>", "<img ismap=\"ismap\" />"); + sanitize("<img usemap=\"something\"/>", "<img usemap=\"something\" />"); + sanitize("<img vspace=\"22\"/>", "<img vspace=\"22\" />"); + sanitize("<img width=\"22\"/>", "<img width=\"22\" />"); + sanitize("<img src=\"http://www.overhere.com/\"></img>", + "<img src=\"http://www.overhere.com/\" />"); + sanitize("<img longdesc=\"http://www.overhere.com/\"></img>", + "<img longdesc=\"http://www.overhere.com/\" />"); + + sanitize("<img src=\"javascript:badness()\"></img>", ""); + sanitize("<img longdesc=\"javascript:badness()\"></img>", ""); + sanitize("<img src=javascript:alert('XSS')>", ""); + sanitize("<img src=JaVaScRiPt:alert('XSS')>", ""); + sanitize("<img src=javascript:alert(\"XSS\")>", ""); + sanitize("<img src=`javascript:alert(\"RSnake says, 'XSS'\")`>", ""); + sanitize("<img \"\"\"><script>alert(\"XSS\")</script>\">", "">"); + sanitize("<img src=# onmouseover=\"alert('xxs')\">", "<img src=\"#\" />"); + sanitize("<img src= onmouseover=\"alert('xxs')\">", "<img src=\"onmouseover=\" />"); + sanitize("<img onmouseover=\"alert('xxs')\">", ""); + sanitize("<img src=/ onerror=\"alert(String.fromCharCode(88,83,83))\"></img>", + "<img src=\"/\" />"); + sanitize("<img src=javascript:a" + + "lert(\n'XSS')>", + ""); + sanitize("<img src=javascr" + + "ipt:a&\n" + + "#0000108ert('XSS" + + "')>", ""); + sanitize("<img src=javascript:ale" + + "rt('XSS')>", ""); + sanitize("<img src=\"jav\tascript:alert('XSS');\">", ""); + sanitize("<img src=\"jav	ascript:alert('XSS');\">", ""); + sanitize("<img src=\"jav
ascript:alert('XSS');\">", ""); + sanitize("<img src=\"jav
ascript:alert('XSS');\">", ""); + sanitize("<img src=java\0script:alert(\\\"XSS\\\")>", ""); + sanitize("<img src=\"  javascript:alert('XSS');\">", ""); + sanitize("<img src=\"javascript:alert('XSS')\"", ""); + sanitize("<img dynsrc=\"javascript:alert('XSS')\">", ""); + sanitize("<img lowsrc=\"javascript:alert('XSS')\">", ""); + sanitize("<img src='vbscript:msgbox(\"XSS\")'>", ""); + sanitize("<img src=\"livescript:[code]\">", ""); + sanitize("<img style=\"xss:expr/*XSS*/ession(alert('XSS'))\">", ""); + } + + public void testInput() { + sanitize("<input accept=\"image/*\"/>", "<input accept=\"image/*\" />"); + sanitize("<input align=\"left\"/>", "<input align=\"left\" />"); + sanitize("<input alt=\"something\"/>", "<input alt=\"something\" />"); + sanitize("<input autocomplete=\"on\"/>", "<input autocomplete=\"on\" />"); + sanitize("<input autofocus=\"autofocus\"/>", "<input autofocus=\"autofocus\" />"); + sanitize("<input checked=\"checked\"/>", "<input checked=\"checked\" />"); + sanitize("<input disabled=\"disabled\"/>", "<input disabled=\"disabled\" />"); + sanitize("<input form=\"1\"/>", "<input form=\"1\" />"); + sanitize("<input formenctype=\"text/plain\"/>", "<input formenctype=\"text/plain\" />"); + sanitize("<input formmethod=\"post\"/>", "<input formmethod=\"post\" />"); + sanitize("<input formnovalidate=\"formnovalidate\"/>", + "<input formnovalidate=\"formnovalidate\" />"); + sanitize("<input formtarget=\"_top\"/>", "<input formtarget=\"_top\" />"); + sanitize("<input height=\"22\"/>", "<input height=\"22\" />"); + sanitize("<input list=\"something\"/>", "<input list=\"something\" />"); + sanitize("<input max=\"1000\"/>", "<input max=\"1000\" />"); + sanitize("<input maxlength=\"10\"/>", "<input maxlength=\"10\" />"); + sanitize("<input min=\"10\"/>", "<input min=\"10\" />"); + sanitize("<input multiple=\"multiple\"/>", "<input multiple=\"multiple\" />"); + sanitize("<input name=\"herman\"/>", "<input name=\"herman\" />"); + sanitize("<input pattern=\"*.*\"/>", "<input pattern=\"*.*\" />"); + sanitize("<input placeholder=\"something\"/>", "<input placeholder=\"something\" />"); + sanitize("<input readonly=\"readonly\"/>", "<input readonly=\"readonly\" />"); + sanitize("<input required=\"required\"/>", "<input required=\"required\" />"); + sanitize("<input size=\"22\"/>", "<input size=\"22\" />"); + sanitize("<input step=\"5\"/>", "<input step=\"5\" />"); + sanitize("<input type=\"button\"/>", "<input type=\"button\" />"); + sanitize("<input value=\"something\"/>", "<input value=\"something\" />"); + sanitize("<input width=\"50\"/>", "<input width=\"50\" />"); + sanitize("<input src=\"http://www.overhere.com/\"></input>", + "<input src=\"http://www.overhere.com/\" />"); + sanitize("<input formaction=\"http://www.overhere.com/\"></input>", + "<input formaction=\"http://www.overhere.com/\" />"); + + sanitize("<input src=\"javascript:badness()\"></input>", ""); + sanitize("<input formaction=\"javascript:badness()\"></input>", ""); + sanitize("<input type=\"image\" src=\"javascript:alert('XSS');\">", + "<input type=\"image\" />"); + sanitize("<input type=\"text\" onchange=\"javascript:alert('XSS');\">", + "<input type=\"text\" />"); + sanitize("<input type=\"button\" onclick=\"javascript:alert('XSS');\">", + "<input type=\"button\" />"); + sanitize("<input type=\"button\" ondblclick=\"javascript:alert('XSS');\">", + "<input type=\"button\" />"); + } + + public void testIns() { + sanitize("<ins>something</ins>", "<ins>something</ins>"); + sanitize("<ins cite=\"javascript:badness();\">something</ins>", "<ins>something</ins>"); + sanitize("<ins cite=\"http://www.reason.com/\">something</ins>", + "<ins cite=\"http://www.reason.com/\">something</ins>"); + sanitize("<ins datetime=\"something\">something</ins>", + "<ins datetime=\"something\">something</ins>"); + } + + public void testKbd() { + sanitize("<kbd>something</kbd>", "<kbd>something</kbd>"); + } + + public void testKeygen() { + sanitize("<keygen/>", "<keygen />"); + sanitize("<keygen autofocus=\"autofocus\"/>", "<keygen autofocus=\"autofocus\" />"); + sanitize("<keygen challenge=\"challenge\"/>", "<keygen challenge=\"challenge\" />"); + sanitize("<keygen disabled=\"disabled\"/>", "<keygen disabled=\"disabled\" />"); + sanitize("<keygen form=\"formId\"/>", "<keygen form=\"formId\" />"); + sanitize("<keygen keytype=\"rsa\"/>", "<keygen keytype=\"rsa\" />"); + sanitize("<keygen name=\"herman\"/>", "<keygen name=\"herman\" />"); + } + + public void testLabel() { + sanitize("<label for=\"elementId\">Something:</label>", "<label>Something:</label>"); + sanitize("<label form=\"formId\">Something:</label>", + "<label form=\"formId\">Something:</label>"); + } + + public void testLegend() { + sanitize("<legend>Something:</legend>", "<legend>Something:</legend>"); + sanitize("<legend align=\"left\">Something:</legend>", + "<legend align=\"left\">Something:</legend>"); + } + + public void testLi() { + sanitize("<li>Something:</li>", "<li>Something:</li>"); + sanitize("<li type=\"a\">Something:</li>", "<li type=\"a\">Something:</li>"); + sanitize("<li value=\"11\">Something:</li>", "<li value=\"11\">Something:</li>"); + } + + public void testLink() { + sanitize("<link charset=\"utf8\"/>", ""); + sanitize("<link href=\"http://www.reason.com/\"/>", ""); + sanitize("<link hreflang=\"fr_CA\"/>", ""); + sanitize("<link media=\"tv\"/>", ""); + sanitize("<link rel=\"alternate\"/>", ""); + sanitize("<link rev=\"something\"/>", ""); + sanitize("<link sizes=\"500x400\"/>", ""); + sanitize("<link target=\"_top\"/>", ""); + sanitize("<link type=\"mimeType\"/>", ""); + sanitize("<link href=\"javascript:alert('XSS');\">", ""); + } + + public void testMain() { + sanitize("<main>something</main>", "<main>something</main>"); + } + + public void testMap() { + sanitize("<map></map>", "<map></map>"); + sanitize("<map name=\"mapname\"></map>", "<map name=\"mapname\"></map>"); + } + + public void testMark() { + sanitize("<mark>something</mark>", "<mark>something</mark>"); + } + + public void testMenu() { + sanitize("<menu></menu>", "<menu></menu>"); + sanitize("<menu label=\"Edit\"></menu>", "<menu label=\"Edit\"></menu>"); + sanitize("<menu type=\"popup\"></menu>", "<menu type=\"popup\"></menu>"); + } + + public void testMenuitem() { + sanitize("<menuitem></menuitem>", "<menuitem></menuitem>"); + sanitize("<menuitem checked=\"checked\"></menuitem>", + "<menuitem checked=\"checked\"></menuitem>"); + sanitize("<menuitem command=\"something\"></menuitem>", + "<menuitem command=\"something\"></menuitem>"); + sanitize("<menuitem default=\"default\"></menuitem>", + "<menuitem default=\"default\"></menuitem>"); + sanitize("<menuitem disabled=\"disabled\"></menuitem>", + "<menuitem disabled=\"disabled\"></menuitem>"); + sanitize("<menuitem icon=\"http://www.reason.com/\"></menuitem>", + "<menuitem icon=\"http://www.reason.com/\"></menuitem>"); + sanitize("<menuitem label=\"something\"></menuitem>", + "<menuitem label=\"something\"></menuitem>"); + sanitize("<menuitem type=\"checkbox\"></menuitem>", + "<menuitem type=\"checkbox\"></menuitem>"); + sanitize("<menuitem radiogroup=\"something\"></menuitem>", + "<menuitem radiogroup=\"something\"></menuitem>"); + + sanitize("<menuitem icon=\"javascript:badness()\"></menuitem>", "<menuitem></menuitem>"); + } + + public void testMeta() { + sanitize("<meta/>", ""); + sanitize("<meta charset=\"utf8\" />", ""); + sanitize("<meta content=\"something\" />", ""); + sanitize("<meta http-equiv=\"refresh\" />", ""); + sanitize("<meta name=\"description\" />", ""); + sanitize("<meta scheme=\"YYYY-MM-DD\" />", ""); + sanitize("<meta http-equiv=\"Link\" content=\"<http://ha.ckers.org/xss.css>; " + + "REL=stylesheet\">", ""); + sanitize("<meta http-equiv=\"refresh\" content=\"0;url=javascript:alert('XSS');\">", ""); + sanitize("<meta http-equiv=\"refresh\" content=\"0;url=data:text/html " + + "base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K\">", ""); + sanitize("<meta http-equiv=\"refresh\" CONTENT=\"0; url=http://;" + + "URL=javascript:alert('XSS');\">", ""); + } + + public void testMeter() { + sanitize("<meter>2 out of 10</meter>", "<meter>2 out of 10</meter>"); + sanitize("<meter form=\"formId\">2 out of 10</meter>", + "<meter form=\"formId\">2 out of 10</meter>"); + sanitize("<meter high=\"10\">2 out of 10</meter>", + "<meter high=\"10\">2 out of 10</meter>"); + sanitize("<meter low=\"10\">2 out of 10</meter>", "<meter low=\"10\">2 out of 10</meter>"); + sanitize("<meter max=\"10\">2 out of 10</meter>", "<meter max=\"10\">2 out of 10</meter>"); + sanitize("<meter min=\"10\">2 out of 10</meter>", "<meter min=\"10\">2 out of 10</meter>"); + sanitize("<meter optimum=\"10\">2 out of 10</meter>", + "<meter optimum=\"10\">2 out of 10</meter>"); + sanitize("<meter value=\"10\">2 out of 10</meter>", + "<meter value=\"10\">2 out of 10</meter>"); + } + + public void testNav() { + sanitize("<nav>something</nav>", "<nav>something</nav>"); + } + + public void testNoframes() { + sanitize("<noframes>No frames!</noframes>", ""); + } + + public void testNoscript() { + sanitize("<noscript>No JavaScript!</noscript>", ""); + } + + public void testObject() { + sanitize("<object>No Objects!</object>", ""); + sanitize("<object type=\"text/x-scriptlet\" data=\"http://ha.ckers.org/scriptlet.html\">" + + "</object>", ""); + } + + public void testOl() { + sanitize("<ol></ol>", "<ol></ol>"); + sanitize("<ol compact=\"compact\"></ol>", "<ol compact=\"compact\"></ol>"); + sanitize("<ol reversed=\"reversed\"></ol>", "<ol reversed=\"reversed\"></ol>"); + sanitize("<ol start=\"11\"></ol>", "<ol start=\"11\"></ol>"); + sanitize("<ol type=\"a\"></ol>", "<ol type=\"a\"></ol>"); + } + + public void testOptgroup() { + sanitize("<optgroup></optgroup>", "<optgroup></optgroup>"); + sanitize("<optgroup disabled=\"disabled\"></optgroup>", + "<optgroup disabled=\"disabled\"></optgroup>"); + sanitize("<optgroup label=\"something\"></optgroup>", + "<optgroup label=\"something\"></optgroup>"); + } + + public void testOption() { + sanitize("<option>something</option>", "<option>something</option>"); + sanitize("<option disabled=\"disabled\">something</option>", + "<option disabled=\"disabled\">something</option>"); + sanitize("<option label=\"something\">something</option>", + "<option label=\"something\">something</option>"); + sanitize("<option selected=\"selected\">something</option>", + "<option selected=\"selected\">something</option>"); + sanitize("<option value=\"volvo\">something</option>", + "<option value=\"volvo\">something</option>"); + } + + public void testOutput() { + sanitize("<output></output>", "<output></output>"); + sanitize("<output for=\"elementId\"></output>", "<output></output>"); + sanitize("<output form=\"formId\"></output>", "<output form=\"formId\"></output>"); + sanitize("<output name=\"something\"></output>", "<output name=\"something\"></output>"); + } + + public void testP() { + sanitize("<p>something</p>", "<p>something</p>"); + sanitize("<p align=\"left\">something</p>", "<p align=\"left\">something</p>"); + } + + public void testParam() { + sanitize("<param name=\"autoplay\" value=\"true\">", ""); + } + + public void testPre() { + sanitize("<pre>something</pre>", "<pre>something</pre>"); + sanitize("<pre width=\"400\">something</pre>", "<pre width=\"400\">something</pre>"); + } + + public void testProgress() { + sanitize("<progress></progress>", "<progress></progress>"); + sanitize("<progress value=\"22\"></progress>", "<progress value=\"22\"></progress>"); + sanitize("<progress max=\"100\"></progress>", "<progress max=\"100\"></progress>"); + } + + public void testQ() { + sanitize("<q>something</q>", "<q>something</q>"); + sanitize("<q cite=\"http://www.reason.com/\">something</q>", + "<q cite=\"http://www.reason.com/\">something</q>"); + sanitize("<q cite=\"javascript:badness()\">something</q>", "<q>something</q>"); + } + + public void testRp() { + sanitize("<rp>something</rp>", "<rp>something</rp>"); + } + + public void testRt() { + sanitize("<rt>something</rt>", "<rt>something</rt>"); + } + + public void testRuby() { + sanitize("<ruby></ruby>", "<ruby></ruby>"); + } + + public void testS() { + sanitize("<s>old skool strikethrough</s>", "<s>old skool strikethrough</s>"); + } + + public void testSamp() { + sanitize("<samp>something</samp>", "<samp>something</samp>"); + } + + public void testScript() { + sanitize("<script>malicious script</script>", ""); + sanitize("<<script>alert(\"XSS\");//<</script>", "<"); + sanitize("<script src=http://ha.ckers.org/xss.js></script>", ""); + sanitize("<script/XSS src=\"http://ha.ckers.org/xss.js\"></script>", ""); + sanitize("<script/src=\"http://ha.ckers.org/xss.js\"></script>", ""); + sanitize("<script src=http://ha.ckers.org/xss.js?< B >", ""); + sanitize("<script src=//ha.ckers.org/.j>", ""); + sanitize("</title><script>alert(\"XSS\");</script>", ""); + sanitize("<script src=\"http://ha.ckers.org/xss.jpg\"></script>", ""); + + String attack = "';alert(String.fromCharCode(88,83,83))//';" + + "alert(String.fromCharCode(88,83,83))//\";\n" + + "alert(String.fromCharCode(88,83,83))//\";" + + "alert(String.fromCharCode(88,83,83))//--\n" + + "></SCRIPT>\">'><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>"; + String defend = "';alert(String.fromCharCode(88,83,83))//';" + + "alert(String.fromCharCode(88,83,83))//";\n" + + "alert(String.fromCharCode(88,83,83))//";" + + "alert(String.fromCharCode(88,83,83))//--\n" + + ">">'>"; + sanitize(attack, defend); + } + + public void testSection() { + sanitize("<section>something</section>", "<section>something</section>"); + } + + public void testSelect() { + sanitize("<select></select>", "<select></select>"); + sanitize("<select autofocus=\"autofocus\"></select>", + "<select autofocus=\"autofocus\"></select>"); + sanitize("<select disabled=\"disabled\"></select>", + "<select disabled=\"disabled\"></select>"); + sanitize("<select form=\"formId\"></select>", "<select form=\"formId\"></select>"); + sanitize("<select multiple=\"multiple\"></select>", + "<select multiple=\"multiple\"></select>"); + sanitize("<select required=\"required\"></select>", + "<select required=\"required\"></select>"); + sanitize("<select size=\"11\"></select>", "<select size=\"11\"></select>"); + } + + public void testSmall() { + sanitize("<small>something</small>", "<small>something</small>"); + } + + public void testSource() { + sanitize("<source/>", "<source />"); + sanitize("<source media=\"something\"/>", "<source media=\"something\" />"); + sanitize("<source type=\"mimeType\"/>", "<source type=\"mimeType\" />"); + sanitize("<source src=\"http://www.reason.com/\"/source>", + "<source src=\"http://www.reason.com/\" />"); + sanitize("<source src=\"javascript:badness()\"/source>", "<source />"); + } + + public void testSpan() { + sanitize("<span style=\"color:blue\">something</span>", + "<span style=\"color:blue\">something</span>"); + } + + public void testStrike() { + sanitize("<strike>something</strike>", "<strike>something</strike>"); + } + + public void testStrong() { + sanitize("<strong>something</strong>", "<strong>something</strong>"); + } + + public void testStyle() { + sanitize("<style>something</style>", ""); + sanitize("<style media=\"something\">something</style>", ""); + sanitize("<style scoped=\"scoped\">something</style>", ""); + sanitize("<style type=\"text/css\">something</style>", ""); + sanitize("<style>li {list-style-image: url(\"javascript:alert('XSS')\");}</style>", ""); + sanitize("<style>@im\\port'\\ja\\vasc\\ript:alert(\"XSS\")';</style>", ""); + sanitize("<style>body{-moz-binding:url(\"http://ha.ckers.org/xssmoz.xml#xss\")}</style>", + ""); + sanitize("<style>@import'http://ha.ckers.org/xss.css';</style>", ""); + sanitize("<style type=\"text/javascript\">alert('XSS');</style>", ""); + sanitize("<style>.XSS{background-image:url(\"javascript:alert('XSS')\");}</style>" + + "<a class=XSS></a>", ""); + sanitize("<style type=\"text/css\">body{background:url(\"javascript:alert('XSS')\")}" + + "</style>", ""); + } + + public void testSub() { + sanitize("<sub>something</sub>", "<sub>something</sub>"); + } + + public void testSummary() { + sanitize("<summary>something</summary>", "<summary>something</summary>"); + } + + public void testSup() { + sanitize("<sup>something</sup>", "<sup>something</sup>"); + } + + public void testTable() { + sanitize("<table></table>", "<table></table>"); + sanitize("<table align=\"left\"></table>", "<table align=\"left\"></table>"); + sanitize("<table bgcolor=\"red\"></table>", "<table bgcolor=\"red\"></table>"); + sanitize("<table border=\"1\"></table>", "<table border=\"1\"></table>"); + sanitize("<table cellpadding=\"1\"></table>", "<table cellpadding=\"1\"></table>"); + sanitize("<table cellspacing=\"1\"></table>", "<table cellspacing=\"1\"></table>"); + sanitize("<table frame=\"void\"></table>", "<table frame=\"void\"></table>"); + sanitize("<table rules=\"none\"></table>", "<table rules=\"none\"></table>"); + sanitize("<table sortable=\"sortable\"></table>", "<table sortable=\"sortable\"></table>"); + sanitize("<table summary=\"something\"></table>", "<table summary=\"something\"></table>"); + sanitize("<table width=\"11\"></table>", "<table width=\"11\"></table>"); + + sanitize("<table background=\"javascript:alert('XSS')\">", "<table></table>"); + } + + public void testTbody() { + sanitize("<tbody></tbody>", "<tbody></tbody>"); + sanitize("<tbody char=\"something\"></tbody>", "<tbody char=\"something\"></tbody>"); + sanitize("<tbody charoff=\"11\"></tbody>", "<tbody charoff=\"11\"></tbody>"); + sanitize("<tbody valign=\"top\"></tbody>", "<tbody valign=\"top\"></tbody>"); + } + + public void testTd() { + sanitize("<td></td>", "<td></td>"); + sanitize("<td abbr=\"something\"></td>", "<td abbr=\"something\"></td>"); + sanitize("<td align=\"left\"></td>", "<td align=\"left\"></td>"); + sanitize("<td axis=\"something\"></td>", "<td axis=\"something\"></td>"); + sanitize("<td bgcolor=\"red\"></td>", "<td bgcolor=\"red\"></td>"); + sanitize("<td char=\"something\"></td>", "<td char=\"something\"></td>"); + sanitize("<td charoff=\"22\"></td>", "<td charoff=\"22\"></td>"); + sanitize("<td colspan=\"33\"></td>", "<td colspan=\"33\"></td>"); + sanitize("<td height=\"44\"></td>", "<td height=\"44\"></td>"); + sanitize("<td nowrap=\"nowrap\"></td>", "<td nowrap=\"nowrap\"></td>"); + sanitize("<td rowspan=\"3\"></td>", "<td rowspan=\"3\"></td>"); + sanitize("<td scope=\"col\"></td>", "<td scope=\"col\"></td>"); + sanitize("<td valign=\"top\"></td>", "<td valign=\"top\"></td>"); + sanitize("<td width=\"55\"></td>", "<td width=\"55\"></td>"); + + sanitize("<td headers=\"headerId\"></td>", "<td></td>"); + sanitize("<td background=\"javascript:alert('XSS')\">", "<td></td>"); + } + + public void testTextarea() { + sanitize("<textarea></textarea>", "<textarea></textarea>"); + sanitize("<textarea autofocus=\"autofocus\"></textarea>", + "<textarea autofocus=\"autofocus\"></textarea>"); + sanitize("<textarea cols=\"1\"></textarea>", "<textarea cols=\"1\"></textarea>"); + sanitize("<textarea disabled=\"disabled\"></textarea>", + "<textarea disabled=\"disabled\"></textarea>"); + sanitize("<textarea form=\"formId\"></textarea>", "<textarea form=\"formId\"></textarea>"); + sanitize("<textarea maxlength=\"2\"></textarea>", "<textarea maxlength=\"2\"></textarea>"); + sanitize("<textarea name=\"something\"></textarea>", + "<textarea name=\"something\"></textarea>"); + sanitize("<textarea placeholder=\"something\"></textarea>", + "<textarea placeholder=\"something\"></textarea>"); + sanitize("<textarea readonly=\"readonly\"></textarea>", + "<textarea readonly=\"readonly\"></textarea>"); + sanitize("<textarea required=\"required\"></textarea>", + "<textarea required=\"required\"></textarea>"); + sanitize("<textarea rows=\"3\"></textarea>", "<textarea rows=\"3\"></textarea>"); + sanitize("<textarea wrap=\"soft\"></textarea>", "<textarea wrap=\"soft\"></textarea>"); + } + + public void testTfoot() { + sanitize("<tfoot></tfoot>", "<tfoot></tfoot>"); + sanitize("<tfoot align=\"left\"></tfoot>", "<tfoot align=\"left\"></tfoot>"); + sanitize("<tfoot char=\"something\"></tfoot>", "<tfoot char=\"something\"></tfoot>"); + sanitize("<tfoot charoff=\"1\"></tfoot>", "<tfoot charoff=\"1\"></tfoot>"); + sanitize("<tfoot valign=\"top\"></tfoot>", "<tfoot valign=\"top\"></tfoot>"); + } + + public void testTh() { + sanitize("<th></th>", "<th></th>"); + sanitize("<th abbr=\"something\"></th>", "<th abbr=\"something\"></th>"); + sanitize("<th align=\"left\"></th>", "<th align=\"left\"></th>"); + sanitize("<th axis=\"something\"></th>", "<th axis=\"something\"></th>"); + sanitize("<th bgcolor=\"red\"></th>", "<th bgcolor=\"red\"></th>"); + sanitize("<th char=\"something\"></th>", "<th char=\"something\"></th>"); + sanitize("<th charoff=\"22\"></th>", "<th charoff=\"22\"></th>"); + sanitize("<th colspan=\"33\"></th>", "<th colspan=\"33\"></th>"); + sanitize("<th height=\"44\"></th>", "<th height=\"44\"></th>"); + sanitize("<th nowrap=\"nowrap\"></th>", "<th nowrap=\"nowrap\"></th>"); + sanitize("<th rowspan=\"3\"></th>", "<th rowspan=\"3\"></th>"); + sanitize("<th scope=\"col\"></th>", "<th scope=\"col\"></th>"); + sanitize("<th sorted=\"reversed\"></th>", "<th sorted=\"reversed\"></th>"); + sanitize("<th valign=\"top\"></th>", "<th valign=\"top\"></th>"); + sanitize("<th width=\"55\"></th>", "<th width=\"55\"></th>"); + + sanitize("<th headers=\"headerId\"></th>", "<th></th>"); + } + + public void testThead() { + sanitize("<thead></thead>", "<thead></thead>"); + sanitize("<thead align=\"left\"></thead>", "<thead align=\"left\"></thead>"); + sanitize("<thead char=\"something\"></thead>", "<thead char=\"something\"></thead>"); + sanitize("<thead charoff=\"1\"></thead>", "<thead charoff=\"1\"></thead>"); + sanitize("<thead valign=\"top\"></thead>", "<thead valign=\"top\"></thead>"); + } + + public void testTime() { + sanitize("<time></time>", "<time></time>"); + sanitize("<time datetime=\"datetime\"></time>", "<time datetime=\"datetime\"></time>"); + } + + public void testTitle() { + sanitize("<title>something</title>", ""); + } + + public void testTr() { + sanitize("<tr></tr>", "<tr></tr>"); + sanitize("<tr align=\"left\"></tr>", "<tr align=\"left\"></tr>"); + sanitize("<tr bgcolor=\"red\"></tr>", "<tr bgcolor=\"red\"></tr>"); + sanitize("<tr char=\"something\"></tr>", "<tr char=\"something\"></tr>"); + sanitize("<tr charoff=\"1\"></tr>", "<tr charoff=\"1\"></tr>"); + sanitize("<tr valign=\"top\"></tr>", "<tr valign=\"top\"></tr>"); + } + + public void testTrack() { + sanitize("<track/>", "<track />"); + sanitize("<track default=\"default\"/>", "<track default=\"default\" />"); + sanitize("<track kind=\"captions\"/>", "<track kind=\"captions\" />"); + sanitize("<track label=\"something\"/>", "<track label=\"something\" />"); + sanitize("<track src=\"http://www.reason.com/\"/>", + "<track src=\"http://www.reason.com/\" />"); + sanitize("<track srclang=\"fr_CA\"/>", "<track srclang=\"fr_CA\" />"); + + sanitize("<track src=\"javascript:badness()\"/>", "<track />"); + } + + public void testTt() { + sanitize("<tt>something</tt>", "<tt>something</tt>"); + } + + public void testU() { + sanitize("<u>something</u>", "<u>something</u>"); + } + + public void testUl() { + sanitize("<ul compact=\"compact\"></ul>", "<ul compact=\"compact\"></ul>"); + sanitize("<ul type=\"disc\"></ul>", "<ul type=\"disc\"></ul>"); + } + + public void testVar() { + sanitize("<var>something</var>", "<var>something</var>"); + } + + public void testVideo() { + sanitize("<video></video>", ""); + } + + public void testWbr() { + sanitize("word1<wbr/>word2", "word1<wbr />word2"); + } + + private void sanitize(String dirtyHTML, String expectedHTML) { + final String cleansedHTML = HtmlSanitizer.sanitizeHtml(dirtyHTML); + assertEquals(expectedHTML, cleansedHTML); + } +} |