Author: jleroux
Date: Thu Jan 5 11:29:26 2017 New Revision: 1777451 URL: http://svn.apache.org/viewvc?rev=1777451&view=rev Log: Implemented: Create and use an OWASP PolicyFactory for content sanitization in ContentWorker for Birt Report Builder (OFBIZ-9166) This is still an incomplete feature because I did not find yet a way to complete the BIRT_REPORT_BUILDER_USAGE_POLICY and had to bypass the sanitization for this case, WIP... This commit has no effect on OFBiz yet. I need to commit this now to continue to work on the main task: OFBIZ-6919 "New implementation of Birt. Easier user possibility of report creation". Modified: ofbiz/trunk/applications/content/src/main/java/org/apache/ofbiz/content/content/ContentWorker.java ofbiz/trunk/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderContentWrapper.java ofbiz/trunk/applications/party/src/main/java/org/apache/ofbiz/party/content/PartyContentWrapper.java ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/category/CategoryContentWrapper.java ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/config/ProductConfigItemContentWrapper.java ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductContentWrapper.java ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductPromoContentWrapper.java ofbiz/trunk/applications/workeffort/src/main/java/org/apache/ofbiz/workeffort/content/WorkEffortContentWrapper.java ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilCodec.java Modified: ofbiz/trunk/applications/content/src/main/java/org/apache/ofbiz/content/content/ContentWorker.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/main/java/org/apache/ofbiz/content/content/ContentWorker.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/content/src/main/java/org/apache/ofbiz/content/content/ContentWorker.java (original) +++ ofbiz/trunk/applications/content/src/main/java/org/apache/ofbiz/content/content/ContentWorker.java Thu Jan 5 11:29:26 2017 @@ -335,18 +335,22 @@ public class ContentWorker implements or String mimeTypeId, boolean cache) throws GeneralException, IOException { Writer writer = new StringWriter(); renderContentAsText(dispatcher, contentId, writer, templateContext, locale, mimeTypeId, null, null, cache); + GenericValue content = EntityQuery.use(dispatcher.getDelegator()).from("Content").where("contentId", contentId).queryOne(); + String contentTypeId = content.getString("contentTypeId"); String rendered = writer.toString(); // According to https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet#XSS_Prevention_Rules_Summary // Normally head is protected by X-XSS-Protection Response Header by default - if (rendered.contains("<script>") - || rendered.contains("<!--") - || rendered.contains("<div") - || rendered.contains("<style>") - || rendered.contains("<span") - || rendered.contains("<input") - || rendered.contains("<iframe") - || rendered.contains("<a")) { - rendered = encoder.sanitize(rendered); + if (!"REPORT".equals(contentTypeId)) { // FIXME here BIRT_REPORT_BUILDER_USAGE_POLICY should be used but I could not tweak it yet: the content of <script> are removed and should not. Also a more annoying no yet spotted issue with contentId dissapearing + if (rendered.contains("<script>") + || rendered.contains("<!--") + || rendered.contains("<div") + || rendered.contains("<style>") + || rendered.contains("<span") + || rendered.contains("<input") + || rendered.contains("<iframe") + || rendered.contains("<a")) { + rendered = encoder.sanitize(rendered, contentTypeId); + } } return rendered; } Modified: ofbiz/trunk/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderContentWrapper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderContentWrapper.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderContentWrapper.java (original) +++ ofbiz/trunk/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderContentWrapper.java Thu Jan 5 11:29:26 2017 @@ -111,7 +111,7 @@ public class OrderContentWrapper impleme if (UtilValidate.isEmpty(outString)) { outString = outString == null? "" : outString; } - outString = encoder.sanitize(outString); + outString = encoder.sanitize(outString, null); if (orderContentCache != null) { orderContentCache.put(cacheKey, outString); } Modified: ofbiz/trunk/applications/party/src/main/java/org/apache/ofbiz/party/content/PartyContentWrapper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/src/main/java/org/apache/ofbiz/party/content/PartyContentWrapper.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/party/src/main/java/org/apache/ofbiz/party/content/PartyContentWrapper.java (original) +++ ofbiz/trunk/applications/party/src/main/java/org/apache/ofbiz/party/content/PartyContentWrapper.java Thu Jan 5 11:29:26 2017 @@ -168,7 +168,7 @@ public class PartyContentWrapper impleme outString = party.getModelEntity().isField(candidateFieldName) ? party.getString(candidateFieldName): ""; outString = outString == null? "" : outString; } - outString = encoder.sanitize(outString); + outString = encoder.sanitize(outString, null); if (partyContentCache != null) { partyContentCache.put(cacheKey, outString); } @@ -176,11 +176,11 @@ public class PartyContentWrapper impleme } catch (GeneralException e) { Debug.logError(e, "Error rendering PartyContent, inserting empty String", module); String candidateOut = party.getModelEntity().isField(candidateFieldName) ? party.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } catch (IOException e) { Debug.logError(e, "Error rendering PartyContent, inserting empty String", module); String candidateOut = party.getModelEntity().isField(candidateFieldName) ? party.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } } Modified: ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/category/CategoryContentWrapper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/category/CategoryContentWrapper.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/category/CategoryContentWrapper.java (original) +++ ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/category/CategoryContentWrapper.java Thu Jan 5 11:29:26 2017 @@ -110,7 +110,7 @@ public class CategoryContentWrapper impl outString = productCategory.getModelEntity().isField(candidateFieldName) ? productCategory.getString(candidateFieldName): ""; outString = outString == null? "" : outString; } - outString = encoder.sanitize(outString); + outString = encoder.sanitize(outString, null); if (categoryContentCache != null) { categoryContentCache.put(cacheKey, outString); } Modified: ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/config/ProductConfigItemContentWrapper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/config/ProductConfigItemContentWrapper.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/config/ProductConfigItemContentWrapper.java (original) +++ ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/config/ProductConfigItemContentWrapper.java Thu Jan 5 11:29:26 2017 @@ -133,7 +133,7 @@ public class ProductConfigItemContentWra outString = productConfigItem.getModelEntity().isField(candidateFieldName) ? productConfigItem.getString(candidateFieldName): ""; outString = outString == null? "" : outString; } - outString = encoder.sanitize(outString); + outString = encoder.sanitize(outString, null); if (configItemContentCache != null) { configItemContentCache.put(cacheKey, outString); } @@ -141,11 +141,11 @@ public class ProductConfigItemContentWra } catch (GeneralException e) { Debug.logError(e, "Error rendering ProdConfItemContent, inserting empty String", module); String candidateOut = productConfigItem.getModelEntity().isField(candidateFieldName) ? productConfigItem.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } catch (IOException e) { Debug.logError(e, "Error rendering ProdConfItemContent, inserting empty String", module); String candidateOut = productConfigItem.getModelEntity().isField(candidateFieldName) ? productConfigItem.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } } Modified: ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductContentWrapper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductContentWrapper.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductContentWrapper.java (original) +++ ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductContentWrapper.java Thu Jan 5 11:29:26 2017 @@ -123,7 +123,7 @@ public class ProductContentWrapper imple outString = product.getModelEntity().isField(candidateFieldName) ? product.getString(candidateFieldName): ""; outString = outString == null? "" : outString; } - outString = encoder.sanitize(outString); + outString = encoder.sanitize(outString, null); if (productContentCache != null) { productContentCache.put(cacheKey, outString); } @@ -131,11 +131,11 @@ public class ProductContentWrapper imple } catch (GeneralException e) { Debug.logError(e, "Error rendering ProductContent, inserting empty String", module); String candidateOut = product.getModelEntity().isField(candidateFieldName) ? product.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } catch (IOException e) { Debug.logError(e, "Error rendering ProductContent, inserting empty String", module); String candidateOut = product.getModelEntity().isField(candidateFieldName) ? product.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } } Modified: ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductPromoContentWrapper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductPromoContentWrapper.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductPromoContentWrapper.java (original) +++ ofbiz/trunk/applications/product/src/main/java/org/apache/ofbiz/product/product/ProductPromoContentWrapper.java Thu Jan 5 11:29:26 2017 @@ -128,7 +128,7 @@ public class ProductPromoContentWrapper outString = productPromo.getModelEntity().isField(candidateFieldName) ? productPromo.getString(candidateFieldName): ""; outString = outString == null? "" : outString; } - outString = encoder.sanitize(outString); + outString = encoder.sanitize(outString, null); if (productPromoContentCache != null) { productPromoContentCache.put(cacheKey, outString); } @@ -136,11 +136,11 @@ public class ProductPromoContentWrapper } catch (GeneralException e) { Debug.logError(e, "Error rendering ProductPromoContent, inserting empty String", module); String candidateOut = productPromo.getModelEntity().isField(candidateFieldName) ? productPromo.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } catch (IOException e) { Debug.logError(e, "Error rendering ProductPromoContent, inserting empty String", module); String candidateOut = productPromo.getModelEntity().isField(candidateFieldName) ? productPromo.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } } Modified: ofbiz/trunk/applications/workeffort/src/main/java/org/apache/ofbiz/workeffort/content/WorkEffortContentWrapper.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/src/main/java/org/apache/ofbiz/workeffort/content/WorkEffortContentWrapper.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/applications/workeffort/src/main/java/org/apache/ofbiz/workeffort/content/WorkEffortContentWrapper.java (original) +++ ofbiz/trunk/applications/workeffort/src/main/java/org/apache/ofbiz/workeffort/content/WorkEffortContentWrapper.java Thu Jan 5 11:29:26 2017 @@ -256,7 +256,7 @@ public class WorkEffortContentWrapper im outString = workEffort.getModelEntity().isField(candidateFieldName) ? workEffort.getString(candidateFieldName): ""; outString = outString == null? "" : outString; } - outString = encoder.sanitize(outString); + outString = encoder.sanitize(outString, null); if (workEffortContentCache != null) { workEffortContentCache.put(cacheKey, outString); } @@ -264,11 +264,11 @@ public class WorkEffortContentWrapper im } catch (GeneralException e) { Debug.logError(e, "Error rendering WorkEffortContent, inserting empty String", module); String candidateOut = workEffort.getModelEntity().isField(candidateFieldName) ? workEffort.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } catch (IOException e) { Debug.logError(e, "Error rendering WorkEffortContent, inserting empty String", module); String candidateOut = workEffort.getModelEntity().isField(candidateFieldName) ? workEffort.getString(candidateFieldName): ""; - return candidateOut == null? "" : encoder.sanitize(candidateOut); + return candidateOut == null? "" : encoder.sanitize(candidateOut, null); } } Modified: ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilCodec.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilCodec.java?rev=1777451&r1=1777450&r2=1777451&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilCodec.java (original) +++ ofbiz/trunk/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilCodec.java Thu Jan 5 11:29:26 2017 @@ -60,7 +60,11 @@ public class UtilCodec { public static interface SimpleEncoder { public String encode(String original); - public String sanitize(String outString); // Only really useful with HTML, else simply calls encode() method + /** + * @deprecated Use {@link #sanitize(String,String)} instead + */ + public String sanitize(String outString); // Only really useful with HTML, else it simply calls encode() method + public String sanitize(String outString, String contentTypeId); // Only really useful with HTML, else it simply calls encode() method } public static interface SimpleDecoder { @@ -76,26 +80,70 @@ public class UtilCodec { } return htmlCodec.encode(IMMUNE_HTML, original); } + /** + * @deprecated Use {@link #sanitize(String,String)} instead + */ public String sanitize(String original) { + return sanitize(original, null); + } + public String sanitize(String original, String contentTypeId) { if (original == null) { return null; } PolicyFactory sanitizer = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.IMAGES).and(Sanitizers.LINKS).and(Sanitizers.STYLES); - if (UtilProperties.getPropertyAsBoolean("owasp", "sanitizer.permissive.policy", false)) { + + if (UtilProperties.getPropertyAsBoolean("owasp", "sanitizer.permissive.policy", false)) {// TODO to be improved to use a (or several) contentTypeId/s if possible sanitizer = sanitizer.and(PERMISSIVE_POLICY); } + if ("REPORT_MASTER".equals(contentTypeId)) { + sanitizer = sanitizer.and(BIRT_REPORT_BUILDER_GENERATION_POLICY); + } + if ("REPORT".equals(contentTypeId)) { + sanitizer = sanitizer.and(BIRT_REPORT_BUILDER_USAGE_POLICY); + } return sanitizer.sanitize(original); } // Given as an example based on rendering cmssite as it was before using the sanitizer. // To use the PERMISSIVE_POLICY set sanitizer.permissive.policy to true. - // Note that I was unable to render </html> and </body>. I guess because are <html> and <body> are not sanitized in 1st place (else the sanitizer makes some damages I found) + // Note that I was unable to render </html> and </body>. I guess because <html> and <body> are not sanitized in 1st place (else the sanitizer makes some damages I found) // You might even want to adapt the PERMISSIVE_POLICY to your needs... Be sure to check https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet before... public static final PolicyFactory PERMISSIVE_POLICY = new HtmlPolicyBuilder() + .allowWithoutAttributes("html", "body") .allowAttributes("id", "class").globally() - .allowElements("html", "body", "div", "center", "span", "table", "td") + .allowElements("div", "center", "span", "table", "td") .allowWithoutAttributes("html", "body", "div", "span", "table", "td") .allowAttributes("width").onElements("table") .toFactory(); + // This is the PolicyFactory used for the Birt Report Builder generation feature ("REPORT_MASTER" contentTypeId) + // It allows to create the OOTB Birt Report Builder example. + // You might need to enhance it for your needs but normally you should not + // In any case be sure to check https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet before changing things here... + public static final PolicyFactory BIRT_REPORT_BUILDER_GENERATION_POLICY = new HtmlPolicyBuilder() + .allowWithoutAttributes("html", "body") + .allowElements("div", "span", "table", "tr", "td") + .allowElements("form", "input", "textarea", "label", "select", "option") + .allowAttributes("id", "class", "name", "value", "onclick").globally() + .allowAttributes("width", "cellspacing").onElements("table") + .allowAttributes("type", "size", "maxlength").onElements("input") + .allowAttributes("cols", "rows").onElements("textarea") + .allowAttributes("class").onElements("td") + .allowAttributes("method").onElements("form") + .toFactory(); + // This is the PolicyFactory used for the Birt Report Builder usage feature. ("REPORT" contentTypeId) + // It allows to use the OOTB Birt Report Builder example. + // You might need to enhance it for your needs but normally you should not + // In any case be sure to check https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet before changing things here... + public static final PolicyFactory BIRT_REPORT_BUILDER_USAGE_POLICY = new HtmlPolicyBuilder() + .allowWithoutAttributes("html", "body") + .allowElements("div", "span", "table", "tr", "td", "script") + .allowElements("form", "input", "textarea", "label", "select", "option") + .allowAttributes("id", "class", "name", "value", "onclick").globally() + .allowAttributes("width", "cellspacing").onElements("table") + .allowAttributes("type", "size", "maxlength").onElements("input") + .allowAttributes("cols", "rows").onElements("textarea") + .allowAttributes("class").onElements("td") + .allowAttributes("method", "onsubmit").onElements("form") + .toFactory(); } public static class XmlEncoder implements SimpleEncoder { @@ -107,7 +155,13 @@ public class UtilCodec { } return xmlCodec.encode(IMMUNE_XML, original); } + /** + * @deprecated Use {@link #sanitize(String,String)} instead + */ public String sanitize(String original) { + return sanitize(original, null); + } + public String sanitize(String original, String contentTypeId) { return encode(original); } } @@ -121,7 +175,13 @@ public class UtilCodec { return null; } } + /** + * @deprecated Use {@link #sanitize(String,String)} instead + */ public String sanitize(String original) { + return sanitize(original, null); + } + public String sanitize(String original, String contentTypeId) { return encode(original); } @@ -143,7 +203,13 @@ public class UtilCodec { } return original; } + /** + * @deprecated Use {@link #sanitize(String,String)} instead + */ public String sanitize(String original) { + return sanitize(original, null); + } + public String sanitize(String original, String contentTypeId) { return encode(original); } } |
Free forum by Nabble | Edit this page |