/* * Copyright (c) 2007-2010, Arshan Dabirsiaghi, Jason Li * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of OWASP nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.owasp.html; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.codec.binary.Base64; import junit.framework.AssertionFailedError; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * This class tests AntiSamy functionality and the basic policy file which * should be immune to XSS and CSS phishing attacks. * * @author Arshan Dabirsiaghi * */ public class AntiSamyTest extends TestCase { static final boolean RUN_KNOWN_FAILURES = false; static final boolean DISABLE_INTERNETS = false; private static HtmlSanitizer.Policy makePolicy(Appendable buffer) { final HtmlStreamRenderer renderer = HtmlStreamRenderer.create( buffer, new Handler() { public void handle(IOException ex) { AssertionFailedError failure = new AssertionFailedError(); failure.initCause(ex); throw failure; } }, new Handler() { public void handle(String errorMessage) { fail(errorMessage); } }); return new HtmlPolicyBuilder() .allowElements( "a", "b", "br", "div", "font", "i", "img", "input", "li", "ol", "p", "span", "td", "ul") .allowAttributes("checked", "type").onElements("input") .allowAttributes("color").onElements("font") .allowAttributes("href").onElements("a") .allowAttributes("src").onElements("img") .allowAttributes("class", "id", "title").globally() .allowAttributes("char").matching( new AttributePolicy() { public String apply( String elementName, String attributeName, String value) { return value.length() == 1 ? value : null; } }).onElements("td") .allowStandardUrlProtocols() .requireRelNofollowOnLinks() .allowStyling() .build(renderer); } private static String sanitize(String html) { StringBuilder sb = new StringBuilder(); HtmlSanitizer.sanitize(html, makePolicy(sb)); return sb.toString(); } private static final String[] BASE64_BAD_XML_STRINGS = new String[] { // first string is // "click here" "PGEgLSBocmVmPSJodHRwOi8vd3d3Lm93YXNwLm9yZyI+Y2xpY2sgaGVyZTwvYT4=", // the rest are randomly generated 300 byte sequences which generate // parser errors, turned into Strings "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", }; @Override protected void setUp() throws Exception { super.setUp(); } @Override protected void tearDown() throws Exception { super.tearDown(); } public static Test suite() { TestSuite suite = new TestSuite(AntiSamyTest.class); return suite; } public void testCompareSpeeds() throws Exception { if (DISABLE_INTERNETS) { return; } long totalTime = 0; long averageTime = 0; int testReps = 15; for (String url : new String[] { "http://slashdot.org/", "http://www.fark.com/", "http://www.cnn.com/", "http://google.com/", "http://www.microsoft.com/en/us/default.aspx", "http://deadspin.com/", }) { URLConnection conn = new URL(url).openConnection(); String ct = guessCharsetFromContentType(conn.getContentType()); InputStreamReader in = new InputStreamReader(conn.getInputStream(), ct); StringBuilder out = new StringBuilder(); char[] buffer = new char[5000]; int read = 0; do { read = in.read(buffer, 0, buffer.length); if (read > 0) { out.append(buffer, 0, read); } } while (read >= 0); in.close(); String html = out.toString(); System.out.println("About to scan: " + url + " size: " + html.length()); if (html.length() > 640000) { System.out.println(" -Maximum input size 640000 exceeded. SKIPPING."); continue; } long startTime = 0; long endTime = 0; for (int j = 0; j < testReps; j++) { startTime = System.nanoTime(); sanitize(html); endTime = System.nanoTime(); System.out.println( " Took " + ((endTime - startTime) / 1000000) + " ms"); totalTime = totalTime + (endTime - startTime); } averageTime = totalTime / testReps; } System.out.println("Total time ms: " + totalTime/1000000L); System.out.println("Average time per rep ms: " + averageTime/1000000L); } /* * Test basic XSS cases. */ public void testScriptAttacks() throws Exception { assertSanitizedDoesNotContain("test", "script"); assertSanitizedDoesNotContain("test", "script"); assertSanitizedDoesNotContain("<<<><", "", "", "onload"); assertSanitizedDoesNotContain("", "onload"); assertSanitizedDoesNotContain("", "alert"); assertSanitizedDoesNotContain("", "alert"); assertSanitizedDoesNotContain("", "iframe"); assertSanitizedDoesNotContain("", "iframe"); assertSanitizedDoesNotContain("", "javascript"); assertSanitizedDoesNotContain("", "javascript"); assertSanitizedDoesNotContain("", "background"); assertSanitizedDoesNotContain("
", "background"); assertSanitizedDoesNotContain("
", "background"); assertSanitizedDoesNotContain(""; assertSanitizedDoesContain(s, "char"); assertSanitizedDoesContain(s, "char"); s = ""; assertSanitizedDoesNotContain(s, "char"); assertSanitizedDoesNotContain(s, "char"); s = ""; assertSanitizedDoesContain(s, "char"); assertSanitizedDoesContain(s, "char"); s = ""; assertSanitizedDoesNotContain(s, "char"); assertSanitizedDoesNotContain(s, "char"); s = ""; assertSanitizedDoesNotContain(s, "char"); assertSanitizedDoesNotContain(s, "char"); } /* privately disclosed issue - cdata bypass */ { String malInput = "]]>"; assertSanitizedDoesNotContain(malInput, "link", "link"); // adds properly even with bad attr assertSanitized("link", "link"); // rel with bad value gets corrected assertSanitized("link", "link"); // correct attribute doesnt get messed with assertSanitized("link", "link"); // if two correct attributes, only one remaining after scan assertSanitized("link", "link"); // test if value is off - does it add? assertSanitizedDoesNotContain("a href=\"blah\">link", "nofollow"); } public void testValidateParamAsEmbed() throws Exception { // let's start with a YouTube embed String input = ""; String expectedOutput = ""; if (RUN_KNOWN_FAILURES) { assertSanitizedDoesContain(input, expectedOutput); } else { assertSanitized(input, ""); } String saxExpectedOutput = ""; if (RUN_KNOWN_FAILURES) { assertSanitizedDoesContain(input, saxExpectedOutput); } else { assertSanitized(input, ""); } // now what if someone sticks malicious URL in the value of the // value attribute in the param tag? remove that param tag input = ""; expectedOutput = ""; saxExpectedOutput = ""; if (RUN_KNOWN_FAILURES) { assertSanitizedDoesContain(input, expectedOutput); } else { assertSanitized(input, ""); } if (RUN_KNOWN_FAILURES) { assertTrue(sanitize(input).equals(saxExpectedOutput)); } else { assertSanitized(input, ""); } // now what if someone sticks malicious URL in the value of the src // attribute in the embed tag? remove that embed tag input = ""; expectedOutput = ""; saxExpectedOutput = ""; if (RUN_KNOWN_FAILURES) { assertSanitizedDoesContain(input, expectedOutput); } else { assertSanitized(input, ""); } if (RUN_KNOWN_FAILURES) { assertSanitizedDoesContain(input, saxExpectedOutput); } else { assertSanitized(input, ""); } } private static void assertSanitizedDoesNotContain( String html, String dangerousContent) { String sanitized = sanitize(html); int index = Strings.toLowerCase(sanitized).indexOf( Strings.toLowerCase(dangerousContent)); assertEquals( "`" + sanitized + "` from `" + html + "` contains `" + dangerousContent + "`", -1, index); } private static void assertSanitizedDoesContain( String html, String dangerousContent) { String sanitized = sanitize(html); int index = Strings.toLowerCase(sanitized).indexOf( Strings.toLowerCase(dangerousContent)); assertTrue( "`" + sanitized + "` from `" + html + "` does not contain `" + dangerousContent + "`", index >= 0); } private static void assertSanitized(String html, String sanitized) { assertEquals(sanitized, sanitize(html)); } private static String guessCharsetFromContentType(String contentType) { Matcher m = Pattern.compile(";\\s*charset=(?:\"([^\"]*)\"|([^\\s;]*))") .matcher(contentType); if (m.find()) { String ct; ct = m.group(1); if (ct != null) { return ct; } ct = m.group(2); if (ct != null) { return ct; } } return "UTF-8"; } }
", "background"); assertSanitizedDoesNotContain("
", "javascript"); assertSanitizedDoesNotContain("
", "javascript"); assertSanitizedDoesNotContain("
", "alert"); assertSanitizedDoesNotContain("
", "alert"); assertSanitizedDoesNotContain("", "alert"); assertSanitizedDoesNotContain("", "alert"); assertSanitizedDoesNotContain("", "ript:alert"); assertSanitizedDoesNotContain("", "ript:alert"); assertSanitizedDoesNotContain("", "javascript"); assertSanitizedDoesNotContain("", "javascript"); assertSanitizedDoesNotContain("", "", "", "", "", "javascript"); assertSanitizedDoesNotContain("", "javascript"); assertSanitizedDoesNotContain("", "", "", "", "\" SRC=\"http://ha.ckers.org/xss.js\">", "\" SRC=\"http://ha.ckers.org/xss.js\">", "\" '' SRC=\"http://ha.ckers.org/xss.js\">", "\" '' SRC=\"http://ha.ckers.org/xss.js\">", "` SRC=\"http://ha.ckers.org/xss.js\">", "` SRC=\"http://ha.ckers.org/xss.js\">", "'>\" SRC=\"http://ha.ckers.org/xss.js\">", "'>\" SRC=\"http://ha.ckers.org/xss.js\">", "document.write(\"PT SRC=\"http://ha.ckers.org/xss.js\">", "script"); assertSanitizedDoesNotContain("PT SRC=\"http://ha.ckers.org/xss.js\">", "script"); assertSanitizedDoesNotContain(""; sanitize(s); sanitize(s); } /* issue #37 - OOM */ { String dirty = "
Poor Bill, couldn't make it to the Museum's story time" + "today, he was so busy shoveling! Well, we sure missed you Bill! So since" + "ou were busy moving snow we read books about snow. We found a clue in one" + "book which revealed a snowplow at the end of the story - we wish it had" + "driven to your driveway Bill. We also read a story which shared fourteen" + "Names For Snow. We'll catch up with you next week....wonder which" + "hat Bill will wear?
Jane"; String s = sanitize(dirty); assertNotNull(s); } /* issue #38 - color problem/color combinations */ { String s = "Test"; String expected = "Test"; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); s = "
Test 3 letter code
"; expected = "
Test 3 letter code
"; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); s = "Test"; expected = "Test"; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); s = "Test"; expected = s; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); if (RUN_KNOWN_FAILURES) { s = "Test"; expected = "Test"; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); } if (RUN_KNOWN_FAILURES) { s = "
Test
"; expected = "
Test
"; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); } s = "Test"; expected = "Test"; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); s = "
Test
"; expected = "
Test
"; assertEquals(expected, sanitize(s)); assertEquals(expected, sanitize(s)); s = "foo@import 'x';bar"; sanitize(s); } /* issue #40 - handling ", "print, projection, screen"); } /* issue #41 - comment handling */ { assertEquals("text ", sanitize("text ")); assertEquals("text ", sanitize("text ")); assertEquals("
text
", sanitize("
text
")); assertEquals("
text
", sanitize("
text
")); assertEquals("
text
", sanitize("
text
")); assertEquals("
text
", sanitize("
text
")); /* * Check to see how nested conditional comments are handled. This is * not very clean but the main goal is to avoid any tags. Not sure * on encodings allowed in comments. */ String input = "
text <[endif]-->
"; String expected = "
text <[endif]-->
"; String output = sanitize(input); assertEquals(expected, output); input = "
text <[endif]-->
"; expected = "
text <[endif]-->
"; output = sanitize(input); assertEquals(expected, output); /* * Regular comment nested inside conditional comment. Test makes * sure */ assertEquals("
text comment <[endif]-->
", sanitize("
text comment <[endif]-->
")); /* * These play with whitespace and have invalid comment syntax. */ assertEquals("
text
", sanitize("
text
")); assertEquals("
text comment
", sanitize("
text comment
")); assertEquals("
text comment
", sanitize("
text comment
")); String attack = "[if lte 8]" + ""; assertEquals(s, "", sanitize(s)); } /* issue #51 - offsite urls with () are found to be invalid */ assertSanitizedDoesNotContain( "test", "("); /* issue #56 - unnecessary spaces */ { String s = "Hello World!"; assertEquals( "Hello World!", sanitize(s)); } /* issue #58 - input not in list of allowed-to-be-empty tags */ { String s = "tgdan g h"; assertEquals("tgdan g h", sanitize(s)); } /* issue #61 - input has newline appended if ends with an accepted tag */ { String dirtyInput = "blah blah."; String s = sanitize(dirtyInput); assertEquals(dirtyInput, s); } /* issue #69 - char attribute should allow single char or entity ref */ { String s = "
testtesttesttesttest