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);
}
}