• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011, Mike Samuel
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 //
8 // Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // Neither the name of the OWASP nor the names of its contributors may
14 // be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 
29 package org.owasp.html;
30 
31 import org.junit.Test;
32 
33 import junit.framework.TestCase;
34 
35 public class SanitizersTest extends TestCase {
36 
37   @Test
testFormatting()38   public static final void testFormatting() {
39     assertEquals("", Sanitizers.FORMATTING.sanitize(null));
40     assertEquals("", Sanitizers.FORMATTING.sanitize(""));
41     assertEquals(
42         "Hello, World!",
43         Sanitizers.FORMATTING.sanitize("Hello, World!"));
44     assertEquals(
45         "Hello, <b>World</b>!",
46         Sanitizers.FORMATTING.sanitize("Hello, <b>World</b>!"));
47     assertEquals(
48         "Hello, <b>World</b>!",
49         Sanitizers.FORMATTING.sanitize(
50             "<p>Hello, <b onclick=alert(1337)>World</b>!</p>"));
51   }
52 
53   @Test
testBlockElements()54   public static final void testBlockElements() {
55     assertEquals("", Sanitizers.BLOCKS.sanitize(null));
56     assertEquals(
57         "Hello, World!",
58         Sanitizers.BLOCKS.sanitize("Hello, World!"));
59     assertEquals(
60         "Hello, World!",
61         Sanitizers.BLOCKS.sanitize("Hello, <b>World</b>!"));
62     assertEquals(
63         "<p>Hello, World!</p>",
64         Sanitizers.BLOCKS.sanitize(
65             "<p onclick=alert(1337)>Hello, <b>World</b>!</p>"));
66   }
67 
68   @Test
testBlockAndFormattingElements()69   public static final void testBlockAndFormattingElements() {
70     PolicyFactory s = Sanitizers.BLOCKS.and(Sanitizers.FORMATTING);
71     PolicyFactory r1 = Sanitizers.BLOCKS.and(Sanitizers.FORMATTING)
72         .and(Sanitizers.BLOCKS);
73     PolicyFactory r2 = Sanitizers.BLOCKS.and(Sanitizers.FORMATTING)
74         .and(Sanitizers.FORMATTING);
75     for (PolicyFactory f : new PolicyFactory[] { s, r1, r2 }) {
76       assertEquals("", f.sanitize(null));
77       assertEquals("Hello, World!", f.sanitize("Hello, World!"));
78       assertEquals("Hello, <b>World</b>!", f.sanitize("Hello, <b>World</b>!"));
79       assertEquals(
80           "<p>Hello, <b>World</b>!</p>",
81           f.sanitize("<p onclick=alert(1337)>Hello, <b>World</b>!</p>"));
82     }
83   }
84 
85   @Test
testStylesAndFormatting()86   public static final void testStylesAndFormatting() {
87     PolicyFactory sanitizer = Sanitizers.FORMATTING
88       .and(Sanitizers.BLOCKS).and(Sanitizers.STYLES).and(Sanitizers.LINKS);
89     String input = "<span style=\"font-weight:bold;"
90       + "text-decoration:underline;background-color:yellow\""
91       + ">aaaaaaaaaaaaaaaaaaaaaaa</span>";
92     String got = sanitizer.sanitize(input);
93     String want = input;
94     assertEquals(want, got);
95   }
96 
97   @Test
testAndIntersects()98   public static final void testAndIntersects() {
99     PolicyFactory restrictedLink = new HtmlPolicyBuilder()
100        .allowElements("a")
101        .allowUrlProtocols("https")
102        .allowAttributes("href", "title").onElements("a")
103        .toFactory();
104     PolicyFactory inline = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
105     String inputHtml =
106         "<a href='http://foo.com/'>Hello, <b>World</b></a>"
107         + "<a title='!' href='https://foo.com/#!'>!</a>";
108     PolicyFactory and1 = restrictedLink.and(inline);
109     PolicyFactory and2 = inline.and(restrictedLink);
110     assertEquals(
111         "https-only links",
112         "Hello, World<a title=\"!\" href=\"https://foo.com/#!\">!</a>",
113         restrictedLink.sanitize(inputHtml));
114     assertEquals(
115         "inline els",
116         "<a href=\"http://foo.com/\" rel=\"nofollow\">Hello, <b>World</b></a>"
117         + "<a href=\"https://foo.com/#!\" rel=\"nofollow\">!</a>",
118         inline.sanitize(inputHtml));
119     assertEquals(
120         "https-only links and inline els",
121         "Hello, <b>World</b>"
122         + "<a title=\"!\" href=\"https://foo.com/#!\" rel=\"nofollow\">!</a>",
123         and1.sanitize(inputHtml));
124     assertEquals(
125         "inline els and https-only links",
126         "Hello, <b>World</b>"
127         + "<a title=\"!\" href=\"https://foo.com/#!\" rel=\"nofollow\">!</a>",
128         and2.sanitize(inputHtml));
129   }
130 
131   @Test
testImages()132   public static final void testImages() {
133     PolicyFactory s = Sanitizers.IMAGES;
134     assertEquals(
135         "foo", s.sanitize("<a href=\"javascript:alert(1337)\">foo</a>"));
136     assertEquals(
137         "<img src=\"foo.gif\" />", s.sanitize("<img src=\"foo.gif\">"));
138     assertEquals(
139         "", s.sanitize("<img src=\"javascript://alert(1337)\">"));
140     assertEquals(
141         "<img src=\"x.gif\" alt=\"y\""
142         + " width=\"96\" height=\"64\" border=\"0\" />",
143         s.sanitize(
144             "<img src=\"x.gif\" alt=\"y\" width=96 height=64 border=0>"));
145     assertEquals(
146         "<img src=\"x.png\" alt=\"y\" height=\"64\" border=\"0\" />",
147         s.sanitize(
148             "<img src=\"x.png\" alt=\"y\" width=\"widgy\" height=64 border=0>")
149         );
150   }
151 
152   @Test
testLinks()153   public static final void testLinks() {
154     PolicyFactory s = Sanitizers.LINKS;
155     assertEquals(
156         "<a href=\"foo.html\" rel=\"nofollow\">Link text</a>",
157         s.sanitize("<a href=\"foo.html\">Link text</a>"));
158     assertEquals(
159         "<a href=\"foo.html\" rel=\"nofollow\">Link text</a>",
160         s.sanitize(
161             "<a href=\"foo.html\" onclick=\"alert(1337)\">Link text</a>"));
162     assertEquals(
163         "<a href=\"http://example.com/x.html\" rel=\"nofollow\">Link text</a>",
164         s.sanitize(
165             "<a href=\"http://example.com/x.html\""
166             + " onclick=\"alert(1337)\">Link text</a>"));
167     assertEquals(
168         "<a href=\"https://example.com/x.html\" rel=\"nofollow\">Link text</a>",
169         s.sanitize(
170             "<a href=\"https://example.com/x.html\""
171             + " onclick=\"alert(1337)\">Link text</a>"));
172     assertEquals(
173         "<a href=\"HTTPS://example.com/x.html\" rel=\"nofollow\">Link text</a>",
174         s.sanitize(
175             "<a href=\"HTTPS://example.com/x.html\""
176             + " onclick=\"alert(1337)\">Link text</a>"));
177     assertEquals(
178         "<a href=\"//example.com/x.html\" rel=\"nofollow\">Link text</a>",
179         s.sanitize(
180             "<a href=\"//example.com/x.html\""
181             + " onclick=\"alert(1337)\">Link text</a>"));
182     assertEquals(
183         "Link text",
184         s.sanitize(
185             "<a href=\"javascript:alert(1337).html\""
186             + " onclick=\"alert(1337)\">Link text</a>"));
187     // Not a link.  Instead, an attempt to intercept URL references that has
188     // not been explicitly allowed.
189     assertEquals(
190         "Header text",
191         s.sanitize("<a name=\"header\" id=\"header\">Header text</a>"));
192   }
193 
194   @Test
testExplicitlyAllowedProtocolsAreCaseInsensitive()195   public static final void testExplicitlyAllowedProtocolsAreCaseInsensitive() {
196     // Issue 24.
197     PolicyFactory s = new HtmlPolicyBuilder()
198         .allowElements("a")
199         .allowAttributes("href").onElements("a")
200         .allowStandardUrlProtocols()
201         .allowUrlProtocols("file")  // Don't try this at home
202         .toFactory();
203     String input = (
204         "<a href='file:///etc/passwd'>Copy and paste this into email</a>"
205         + "<a href='FILE:///etc/passwd'>Or this one</a>"
206         + "<a href='F\u0130LE:///etc/passwd'>not with Turkish dotted I's</a>"
207         + "<a href='fail:///etc/passed'>The fail protocol needs to happen</a>");
208     String want = (
209         "<a href=\"file:///etc/passwd\">Copy and paste this into email</a>"
210         + "<a href=\"FILE:///etc/passwd\">Or this one</a>"
211         + "not with Turkish dotted I&#39;s"
212         + "The fail protocol needs to happen");
213     assertEquals(want, s.sanitize(input));
214   }
215 
216   @Test
testIssue9StylesInTables()217   public static final void testIssue9StylesInTables() {
218     String input = ""
219         + "<table style=\"color: rgb(0, 0, 0);"
220         + " font-family: Arial, Geneva, sans-serif;\">"
221         + "<tbody>"
222         + "<tr>"
223         + "<th>Column One</th><th>Column Two</th>"
224         + "</tr>"
225         + "<tr>"
226         + "<td align=\"center\""
227         + " style=\"background-color: rgb(255, 255, 254);\">"
228         + "<font size=\"2\">Size 2</font></td>"
229         + "<td align=\"center\""
230         + " style=\"background-color: rgb(255, 255, 254);\">"
231         + "<font size=\"7\">Size 7</font></td>"
232         + "</tr>"
233         + "</tbody>"
234         + "</table>";
235     PolicyFactory s = new HtmlPolicyBuilder()
236         .allowElements("table", "tbody", "thead", "tr", "td", "th")
237         .allowCommonBlockElements()
238         .allowCommonInlineFormattingElements()
239         .allowStyling()
240         .allowAttributes("align").matching(true, "left", "center", "right")
241           .onElements("table", "tr", "td", "th")
242         .allowAttributes("size").onElements("font", "img")
243         .toFactory();
244     String sanitized = ""
245         + "<table style=\"color:rgb( 0 , 0 , 0 );"
246         + "font-family:&#39;arial&#39; , &#39;geneva&#39; , sans-serif\">"
247         + "<tbody>"
248         + "<tr>"
249         + "<th>Column One</th><th>Column Two</th>"
250         + "</tr>"
251         + "<tr>"
252         + "<td align=\"center\""
253         + " style=\"background-color:rgb( 255 , 255 , 254 )\">"
254         + "<font size=\"2\">Size 2</font></td>"
255         + "<td align=\"center\""
256         + " style=\"background-color:rgb( 255 , 255 , 254 )\">"
257         + "<font size=\"7\">Size 7</font></td>"
258         + "</tr>"
259         + "</tbody>"
260         + "</table>";
261     assertEquals(sanitized, s.sanitize(input));
262   }
263 
264   @Test
testSkipIfEmptyUnionsProperly()265   public static final void testSkipIfEmptyUnionsProperly() {
266     // Issue 23
267     PolicyFactory extras = new HtmlPolicyBuilder()
268         .allowWithoutAttributes("span", "div")
269         .allowElements("span", "div", "textarea")
270         // This is not the proper way to require the attribute disabled on
271         // textareas.  This is a test.  This is only a test.
272         .allowAttributes("disabled").onElements("textarea")
273         .disallowWithoutAttributes("textarea")
274         .toFactory();
275     PolicyFactory policy = Sanitizers.FORMATTING
276         .and(Sanitizers.BLOCKS)
277         .and(Sanitizers.IMAGES)
278         .and(Sanitizers.STYLES)
279         .and(extras);
280     String input =
281         "<textarea>text</textarea><textarea disabled></textarea>"
282         + "<div onclick='redirect()'><span>Styled by span</span></div>";
283     String want = "text<textarea disabled=\"disabled\"></textarea>"
284         + "<div><span>Styled by span</span></div>";
285     assertEquals(want, policy.sanitize(input));
286   }
287 }
288