From 2d3d047c6bf93868ee5f53c5b74f0f5115c64081 Mon Sep 17 00:00:00 2001 From: tdelafosse Date: Tue, 24 Sep 2013 22:43:48 +0200 Subject: [PATCH] Safe HTML macro --- .../xwiki-rendering-macro-html/pom.xml | 6 ++ .../rendering/internal/macro/html/HTMLMacro.java | 60 +++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/xwiki-rendering-macros/xwiki-rendering-macro-html/pom.xml b/xwiki-rendering-macros/xwiki-rendering-macro-html/pom.xml index 3ba768d..571609b 100644 --- a/xwiki-rendering-macros/xwiki-rendering-macro-html/pom.xml +++ b/xwiki-rendering-macros/xwiki-rendering-macro-html/pom.xml @@ -55,6 +55,12 @@ ${project.version} test + + + org.jsoup + jsoup + 1.7.2 + diff --git a/xwiki-rendering-macros/xwiki-rendering-macro-html/src/main/java/org/xwiki/rendering/internal/macro/html/HTMLMacro.java b/xwiki-rendering-macros/xwiki-rendering-macro-html/src/main/java/org/xwiki/rendering/internal/macro/html/HTMLMacro.java index 1180c29..e6a60bd 100644 --- a/xwiki-rendering-macros/xwiki-rendering-macro-html/src/main/java/org/xwiki/rendering/internal/macro/html/HTMLMacro.java +++ b/xwiki-rendering-macros/xwiki-rendering-macro-html/src/main/java/org/xwiki/rendering/internal/macro/html/HTMLMacro.java @@ -31,10 +31,14 @@ import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.safety.Whitelist; +import org.slf4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xwiki.component.annotation.Component; +import org.xwiki.configuration.ConfigurationSource; import org.xwiki.rendering.block.Block; import org.xwiki.rendering.block.Block.Axes; import org.xwiki.rendering.block.MacroBlock; @@ -92,7 +96,32 @@ * Used to search for inner macros. */ private static final ClassBlockMatcher MACROBLOCKMATCHER = new ClassBlockMatcher(MacroBlock.class); - + + /** + * List of additional tags to authorize. + */ + private static final String[] TAG_WHITELIST = + {"div", "form", "input", "label", "optgroup", "option", "select", "span", "textarea"}; + + /** + * List of additional attributes to authorize. + */ + private static final String[] ATTRIBUTE_WHITELIST = + {"checked", "cols", "class", "id", "for", "label", "method", "name", "rows", "selected", "size", "style", "type", "value"}; + + /** + * Logger; + */ + @Inject + private Logger logger; + + /** + * Obtain configuration from the xwiki.properties file. + */ + @Inject + @Named("xwikiproperties") + private ConfigurationSource configuration; + /** * To clean the passed HTML so that it's valid XHTML (this is required since we use an XML parser to parse it). */ @@ -152,6 +181,11 @@ public boolean supportsInlineMode() } else if (context.getTransformationContext().isRestricted()) { throw new MacroExecutionException("The HTML macro may not be used with clean=\"false\" in this context."); } + + if(!isValid(normalizedContent)) { + logger.debug("Invalid content for the HTML macro : " + normalizedContent); + throw new MacroExecutionException("The content is invalid."); + } blocks = Arrays.asList((Block) new RawBlock(normalizedContent, XHTML_SYNTAX)); } else { @@ -295,4 +329,28 @@ private HTMLCleanerConfiguration getCleanerConfiguration(MacroTransformationCont return cleanerConfiguration; } + + /** + * @param content The HTML content to valid. + * @return true if the content passed is valid. + */ + private boolean isValid(String content) + { + Whitelist whitelist = Whitelist.relaxed(); + //Add some tags for enabling users to make forms. + whitelist.addTags(TAG_WHITELIST); + // Retrieve additional tags to be allowed from xwikiproperties. + String[] authorizedTags = getAuthorizedTags(); + whitelist.addTags(authorizedTags); + //Add some attributes + whitelist.addAttributes(":all", ATTRIBUTE_WHITELIST); + return Jsoup.isValid(content, whitelist); + } + + private String[] getAuthorizedTags() + { + String[] defaultTags = {}; + String[] authorizedTags = configuration.getProperty("rendering.macro.html.authorizedTags", defaultTags); + return authorizedTags; + } } -- 1.7.10.4