Skip to content

Commit

Permalink
enable FEATURE_SECURE_PROCESSING for the XSLT processor
Browse files Browse the repository at this point in the history
  • Loading branch information
rbri committed Jan 24, 2023
1 parent d75f212 commit 641325b
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 13 deletions.
3 changes: 3 additions & 0 deletions src/changes/changes.xml
Expand Up @@ -8,6 +8,9 @@

<body>
<release version="2.70.0" date="Febuary xx, 2023" description="Bugfixes">
<action type="fix" dev="rbri">
Enable FEATURE_SECURE_PROCESSING for the XSLT processor.
</action>
<action type="add" dev="rbri">
Document disabling of website certificate check in the FAQ.
</action>
Expand Down
Expand Up @@ -26,6 +26,7 @@
import java.util.HashMap;
import java.util.Map;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
Expand Down Expand Up @@ -128,6 +129,11 @@ private Object transform(final Node source) {

final TransformerFactory transformerFactory = TransformerFactory.newInstance();

// By default, the JDK turns on FSP for DOM and SAX parsers and XML schema validators,
// which sets a number of processing limits on the processors. Conversely, by default,
// the JDK turns off FSP for transformers and XPath, which enables extension functions for XSLT and XPath.
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

final SgmlPage page = sourceDomNode.getPage();
if (page != null && page.getWebClient().getBrowserVersion()
.hasFeature(JS_XSLT_TRANSFORM_INDENT)) {
Expand Down
Expand Up @@ -47,7 +47,12 @@ public class ErrorOutputChecker implements MethodRule {
// Quercus
Pattern.compile(".*com.caucho.quercus.servlet.QuercusServlet initImpl\r?\n"),
Pattern.compile(".*QuercusServlet starting as QuercusServletImpl\r?\n"),
Pattern.compile(".*Quercus finished initialization in \\d*ms\r?\n")
Pattern.compile(".*Quercus finished initialization in \\d*ms\r?\n"),

// Xalan
Pattern.compile("ERROR:\\s*'Use of the extension function "
+ "'http://xml\\.apache\\.org/xalan/java/.*' "
+ "is not allowed when the secure processing feature is set to true\\.'\r?\n"),
};

/**
Expand Down
Expand Up @@ -23,6 +23,7 @@
import com.gargoylesoftware.htmlunit.WebDriverTestCase;
import com.gargoylesoftware.htmlunit.junit.BrowserRunner;
import com.gargoylesoftware.htmlunit.junit.BrowserRunner.Alerts;
import com.gargoylesoftware.htmlunit.junit.BrowserRunner.HtmlUnitNYI;
import com.gargoylesoftware.htmlunit.util.MimeType;

/**
Expand All @@ -38,28 +39,49 @@ public class XSLTProcessorTest extends WebDriverTestCase {
* @throws Exception if the test fails
*/
@Test
@Alerts("exception")
@Alerts(DEFAULT = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<head></head><body> <h2>My CD Collection</h2> "
+ "<ul><li>Empire Burlesque (Bob Dylan)</li></ul> </body></html>",
FF = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<body><h2>My CD Collection</h2>"
+ "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
FF_ESR = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<body><h2>My CD Collection</h2>"
+ "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
IE = "exception")
@HtmlUnitNYI(CHROME = "<html><body><h2>My CD Collection</h2>"
+ "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
EDGE = "<html><body><h2>My CD Collection</h2>"
+ "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
FF = "<html><body><h2>My CD Collection</h2>"
+ "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>",
FF_ESR = "<html><body><h2>My CD Collection</h2>"
+ "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>")
public void test() throws Exception {
final String html = "<html><head>\n"
+ "<script>\n"
+ LOG_TITLE_FUNCTION

+ " function createXmlDocument() {\n"
+ " return document.implementation.createDocument('', '', null);\n"
+ " }\n"

+ " function loadXMLDocument(url) {\n"
+ " var xhttp = new XMLHttpRequest();\n"
+ " xhttp.open('GET', url, false);\n"
+ " xhttp.send();\n"
+ " return xhttp.responseXML;\n"
+ " }"

+ " function test() {\n"
+ " try {\n"
+ " var xmlDoc = createXmlDocument();\n"
+ " xmlDoc.async = false;\n"
+ " xmlDoc.load('" + URL_SECOND + "1');\n"

+ " var xslDoc;\n"
+ " xslDoc = createXmlDocument();\n"
+ " xslDoc.async = false;\n"
+ " xslDoc.load('" + URL_SECOND + "2');\n"
+ " var xmlDoc = loadXMLDocument('" + URL_SECOND + "1');\n"
+ " var xslDoc = loadXMLDocument('" + URL_SECOND + "2');\n"

+ " var processor = new XSLTProcessor();\n"
+ " processor.importStylesheet(xslDoc);\n"
+ " var newDocument = processor.transformToDocument(xmlDoc);\n"
+ " log(new XMLSerializer().serializeToString(newDocument.documentElement).length);\n"
+ " newDocument = processor.transformToDocument(xmlDoc.documentElement);\n"
+ " log(newDocument.documentElement);\n"
+ " log(new XMLSerializer().serializeToString(newDocument.documentElement));\n"
+ " } catch(e) { log('exception'); }\n"
+ " }\n"

Expand Down Expand Up @@ -199,4 +221,68 @@ public void browserDetection() throws Exception {
+ "</body></html>";
loadPageVerifyTitle2(html);
}

/**
* @throws Exception if the test fails
*/
@Test
@Alerts(DEFAULT = {"preparation done", "null"},
FF = {"preparation done", "exception"},
FF_ESR = {"preparation done", "exception"},
IE = "exception")
@HtmlUnitNYI(CHROME = {"preparation done", "exception"},
EDGE = {"preparation done", "exception"})
public void testSecurity() throws Exception {
final String html = "<html><head>\n"
+ "<script>\n"
+ LOG_TITLE_FUNCTION

+ " function createXmlDocument() {\n"
+ " return document.implementation.createDocument('', '', null);\n"
+ " }\n"

+ " function loadXMLDocument(url) {\n"
+ " var xhttp = new XMLHttpRequest();\n"
+ " xhttp.open('GET', url, false);\n"
+ " xhttp.send();\n"
+ " return xhttp.responseXML;\n"
+ " }"

+ " function test() {\n"
+ " try {\n"
+ " var xmlDoc = loadXMLDocument('" + URL_SECOND + "1');\n"
+ " var xslDoc = loadXMLDocument('" + URL_SECOND + "2');\n"

+ " var processor = new XSLTProcessor();\n"
+ " processor.importStylesheet(xslDoc);\n"
+ " log('preparation done');\n"
+ " var newDocument = processor.transformToDocument(xmlDoc);\n"
+ " log(newDocument);\n"
+ " } catch(e) { log('exception'); }\n"
+ " }\n"
+ "</script></head>"
+ "<body onload='test()'>\n"
+ "</body></html>";

final String xml
= "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+ "<s></s>";

final String xsl
= " <xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" "
+ "xmlns:rt=\"http://xml.apache.org/xalan/java/java.lang.Runtime\" "
+ "xmlns:ob=\"http://xml.apache.org/xalan/java/java.lang.Object\">\r\n"
+ " <xsl:template match='/'>\n"
+ " <xsl:variable name='rtobject' select='rt:getRuntime()'/>\n"
+ " <xsl:variable name=\"rtString\" select=\"ob:toString($rtobject)\"/>\n"
+ " <xsl:value-of select=\"$rtString\"/>\n"
+ " </xsl:template>\r\n"
+ " </xsl:stylesheet>";

final MockWebConnection conn = getMockWebConnection();
conn.setResponse(new URL(URL_SECOND, "1"), xml, MimeType.TEXT_XML);
conn.setResponse(new URL(URL_SECOND, "2"), xsl, MimeType.TEXT_XML);

loadPageVerifyTitle2(html);
}
}

0 comments on commit 641325b

Please sign in to comment.