001 // Copyright (c) 2011, Mike Samuel 002 // All rights reserved. 003 // 004 // Redistribution and use in source and binary forms, with or without 005 // modification, are permitted provided that the following conditions 006 // are met: 007 // 008 // Redistributions of source code must retain the above copyright 009 // notice, this list of conditions and the following disclaimer. 010 // Redistributions in binary form must reproduce the above copyright 011 // notice, this list of conditions and the following disclaimer in the 012 // documentation and/or other materials provided with the distribution. 013 // Neither the name of the OWASP nor the names of its contributors may 014 // be used to endorse or promote products derived from this software 015 // without specific prior written permission. 016 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 017 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 018 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 019 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 020 // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 021 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 022 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 024 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 025 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 026 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 027 // POSSIBILITY OF SUCH DAMAGE. 028 029 package org.owasp.html; 030 031 /** 032 * Pre-packaged HTML sanitizer policies. 033 * 034 * <p> 035 * These policies can be used to sanitize content. 036 * </p> 037 * <pre> 038 * Sanitizers.FORMATTING.sanitize({@code "<b>Hello, World!</b>"}) 039 * </pre> 040 * and can be chained 041 * <pre> 042 * PolicyFactory sanitizer = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS); 043 * System.out.println(sanitizer.sanitize({@code "<p>Hello, <b>World!</b>"})); 044 * </pre> 045 * 046 * <p> 047 * For more fine-grained control over sanitization, use 048 * {@link HtmlPolicyBuilder}. 049 * </p> 050 * 051 * @author Mike Samuel <mikesamuel@gmail.com> 052 */ 053 public final class Sanitizers { 054 055 /** 056 * Allows common formatting elements including {@code <b>}, {@code <i>}, etc. 057 */ 058 public static final PolicyFactory FORMATTING = new HtmlPolicyBuilder() 059 .allowCommonInlineFormattingElements().toFactory(); 060 061 /** 062 * Allows common block elements including <code><p></code>, 063 * <code><h1></code>, etc. 064 */ 065 public static final PolicyFactory BLOCKS = new HtmlPolicyBuilder() 066 .allowCommonBlockElements().toFactory(); 067 068 /** 069 * Allows certain safe CSS properties in {@code style="..."} attributes. 070 */ 071 public static final PolicyFactory STYLES = new HtmlPolicyBuilder() 072 .allowStyling().toFactory(); 073 074 /** 075 * Allows HTTP, HTTPS, MAILTO, and relative links. 076 */ 077 public static final PolicyFactory LINKS = new HtmlPolicyBuilder() 078 .allowStandardUrlProtocols().allowElements("a") 079 .allowAttributes("href").onElements("a").requireRelNofollowOnLinks() 080 .toFactory(); 081 082 private static final AttributePolicy INTEGER = new AttributePolicy() { 083 public String apply( 084 String elementName, String attributeName, String value) { 085 int n = value.length(); 086 if (n == 0) { return null; } 087 for (int i = 0; i < n; ++i) { 088 char ch = value.charAt(i); 089 if (ch == '.') { 090 if (i == 0) { return null; } 091 return value.substring(0, i); // truncate to integer. 092 } else if (!('0' <= ch && ch <= '9')) { 093 return null; 094 } 095 } 096 return value; 097 } 098 }; 099 100 /** 101 * Allows {@code <img>} elements from HTTP, HTTPS, and relative sources. 102 */ 103 public static final PolicyFactory IMAGES = new HtmlPolicyBuilder() 104 .allowUrlProtocols("http", "https").allowElements("img") 105 .allowAttributes("alt", "src").onElements("img") 106 .allowAttributes("border", "height", "width").matching(INTEGER) 107 .onElements("img") 108 .toFactory(); 109 110 private Sanitizers() { 111 // Uninstantiable. 112 } 113 }