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("\n" + "\n" + "HTML E-mail\n" + "\n" + "\n" + "\n" + "Body here\n" + "
\n" + "Link to Google Search!\n" + "
\n" + "
\n" + "I am a link!\n" + "
\n" + "Moar body here\n" + "\n" + "" , "\n" + "\n" + "\n" + "\n" + "\n" + "
\n" + "Body here\n" + "
\n" + "Link to Google Search!\n" + "
\n" + "
\n" + "I am a link!\n" + "
\n" + "Moar body here\n" + "
\n"); } public void testXSS() { sanitize("'';!--\"=&{()}", "'';!--"=&{()}"); sanitize("", ""); sanitize("\\\";alert('XSS');//", "\\";alert('XSS');//"); sanitize("
", "
"); sanitize("", ""); sanitize("", ""); sanitize("¼script¾alert(¢XSS¢)¼/script¾", "¼script¾alert(¢XSS¢)¼/script¾"); sanitize("cript:alert('XSS')\">", ""); sanitize("", ""); sanitize("", ""); sanitize("\n" + "\n" + "\n" + "alert(\"XSS\")" + "\">\n" + "", "
\n" + "\n" + "\n" + "">\n" + "
"); } /** * Technically, RFC 2392 doesn't limit where CID urls may appear. But, Webview is unhappy * handling them within link tags, so we only allow them in img src attributes until we see a * reason to expand their acceptance. */ public void testCIDurls() { sanitize("", ""); sanitize("", ""); sanitize("", ""); sanitize("", ""); sanitize("", ""); sanitize("", ""); } // 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("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); } // 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("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); } public void testTrimmingUrls() { // todo Gmail strips the leading space on this href // sanitize("
Send mail", // "Send mail"); sanitize("Send mail", "Send mail"); // todo Gmail strips the trailing space on this href // sanitize("Send mail ", // "Send mail"); sanitize("Send mail", "Send mail"); // todo Gmail strips the leading and trailing spaces on this href // sanitize("Send mail ", // "Send mail"); sanitize("Send mail", "Send mail"); } public void testDangerousHtml() { // body tag is translated to div tag sanitize("arr", "
arr
"); sanitize("
arr
", "
arr
"); sanitize("arr", "arr"); // mailto: URLs on images are too easy to turn into DOS attacks sanitize("", ""); sanitize("", ""); sanitize("", ""); sanitize("", ""); sanitize("", ""); sanitize("", ""); // todo Gmail doesn't escape the @ sign; OWASP does by default // sanitize("Send mail ", // "Send mail "); sanitize("Send mail ", "Send mail "); } public void testSanitizingImgsWithoutSchemes() { sanitize("", // ""); // todo Gmail doesn't escape the = signs ""); } public void testAdditionalURISchemes() { // todo Gmail keeps a destinationless link; OWASP strips the a link completely // sanitize("link1", "link1"); sanitize("link1", "link1"); // todo Gmail keeps a destinationless a link; OWASP strips the a link completely // sanitize("link2", "link2"); sanitize("link2", "link2"); } public void testBackgroundAttribute() { sanitize("
stuff
more stuff
", "
stuff
more stuff
"); } public void testInputImage() { sanitize("", ""); } 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("", ""); } 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("asdf", // "asdf"); sanitize("asdf", "asdf"); } public void testNoJS() { // todo Gmail leaves this CSS in place and escapes it; OWASP removes it all // sanitize("", // ""); sanitize("", ""); } public void testNoStyleElementByDefault() { sanitize("" + "

test

", "

test

"); } public void testMessageFormation() { sanitize("
This is a simple message
", "
This is a simple message
"); sanitize("
This is a simple message", "
This is a simple message
"); sanitize("This is a simple message
", "
This is a simple message
"); sanitize("This is a simple message
", "This is a simple message"); } public void testViolatingTags() { sanitize("html to ruin your site" + "" + "" + "" + "" + "" + "This page requires frames!" + "" + "" + "" + " " + "" + "" + "
" + "Execute this
" , "
" + "" + "
" + "Execute this
" ); sanitize("Include this:
" + "" + "" + "
" + "
" + "" + "" + "
" , "Include this:
" + "
" + "
" + "" + "" + "
" ); } public void testLinks() { sanitize("" + "click here" + "here" + "or here" , "" + "click here" + "here" + "or here" ); } public void testExternalLinks() { sanitize("This is a test here " + "" + "" + "" + " " + "hey" , "This is a test here " + "" + "" + " " ); } public void testNewHtmlWhitelist() { sanitize("link" + "BOLD" + "italics" + "underlined" + "
break
break" + "Big_font_gone" , "link" + "BOLD" + "italics" + "underlined" + "
break
break" + "Big_font_gone" ); } public void testRemoveBackticksInAttributes() { // IE treats backticks as quotes when re-serializing, but not when parsing sanitize("\"``onload=alert(1)\"", "\"``onload=alert(1)"); sanitize("\"'``onload=alert(1)'\"", "\"'``onload=alert(1)'"); sanitize("``onload=alert(1)\"", "\"``onload=alert(1)"); // Make sure we're not fooled by escaped backticks sanitize("\"``onload=alert(1)\"", "\"``onload=alert(1)"); sanitize("\"``onload=alert(1)\"", "\"``onload=alert(1)"); // Misc. dangerous cases: sanitize("`x`onload=alert(1)", "\"`x`onload=alert(1)"); sanitize("foo`x`onload=alert(1)", "\"foo`x`onload=alert(1)"); sanitize("\"`whatever\"Hello world ` onload=alert(1)
", "\"`whateverHello world ` onload=alert(1)
"); // The tokenizer doesn't see these as entities because they lack a trailing semicolon, so it // escapes the leading ampersands. sanitize("\"``onload=alert(1)\"", "\"`&#x000060onload=alert(1)"); // Here there are no actual backticks, though there would be if we (or IE) did repeated // unescaping. sanitize("\"&#x000060&#x000060onload=alert(2)\"", "\"&#x000060&#x000060onload=alert(2)\""); sanitize("\"&#x000060&#x000060onload=alert(2)\"", "\"&#x000060&#x000060onload=alert(2)\""); } public void testMakeSafeStyle() { sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); // check for CSS3 border-radius sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); // allow positive margins sanitize("
", "
"); sanitize("
", "
"); // negative margin would allow it to slip out of the box sanitize("
", "
"); // allow positive text-ident sanitize("
", "
"); sanitize("
", "
"); // todo Gmail disallows negative text-indents; OWASP is fine with them // negative text-indent would allow it to slip out of the box // sanitize("
", "
"); sanitize("
", "
"); } public void testMakeSafeStyleWithQuotedStrings() { sanitize("
", "
" + "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); } public void testSeriouslyNoBackgroundImages() { sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); } public void testExpression() { sanitize("
", "
"); } public void testStrayUrlConsideredHarmful() { sanitize("
", "
"); sanitize("
", "
"); } public void testObjectionableFunctions() { sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); } public void testAbsolutePositionBanned() { sanitize("
", "
"); } public void testNoTextShadow() { // todo Gmail disallows this text-shadow; OWASP is fine with it // sanitize("
", "
"); sanitize("
", "
"); } public void testToStyle() { sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); sanitize("
", "
"); } public void testNoColorStrings() { sanitize("
", "
"); } public void testTolerateMalformedBorder() { sanitize("
", "
"); } public void testRgba() { sanitize("
", "
"); } public void testFontStyle() { // todo Gmail accepts !important while OWASP discards it; this is only beauty, not security // sanitize("
", // "
"); sanitize("
", "
"); // todo Gmail accepts !important while OWASP discards it; this is only beauty, not security // sanitize("
", // "
"); sanitize("
", "
"); sanitize("
", "
"); } private void sanitize(String dirtyHTML, String expectedHTML) { final String cleansedHTML = HtmlSanitizer.sanitizeHtml(dirtyHTML); assertEquals(expectedHTML, cleansedHTML); } }