Repository navigation
Harden XML with Commons Secure XML - #2635
garydgregory wants to merge 6 commits into
Conversation
In addition,remove "disallow-doctype-decl". Chances are the motivation behind the setting is the same as with Tika: This is not about banning DOCTYPE, just preventing XXE injection.
|
thank you for the PR. Can you share a bit what the advantages are of using this library? |
|
Hi @mattrpav CC @ppkarwasz Commons Secure XML is a tiny library that:
HTH! |
|
Oh, another use case is (like me) when you offer an option to embedded AMQ, AMQ is not in full control of the classpath. When the JRE resolves the JAXP implementation, you may get implementation dependent issues. We talk about this in the introduction in https://commons.apache.org/proper/commons-secure-xml/apidocs/index.html#tldr if you care for the details. |
| trySetFeature(builderFactory,"http://apache.org/xml/features/nonvalidating/load-external-dtd", false); | ||
|
|
||
| return builderFactory; | ||
| return SecureDocumentBuilderFactory.newInstance(); |
There was a problem hiding this comment.
What about inlinining this method and deprecating this class?
This method has only two callers and both could just use newNSDocumentBuilder that we are about to be introduced in version 1.1.0.
A small difference in the two callers would need to be settled:
RuntimeConfigurationBroker#loadConfigurationuses a namepace-aware parser and retrieves the broker element via:doc.getElementsByTagNameNS("*","broker").item(0);
CreateCommand#copyActivemqConfuses a namespace-unaware parser and retrieves the same broker element viaXPath.
I think both could use a namespace-aware parser
There was a problem hiding this comment.
I implemented @ppkarwasz 's suggestion in commit 6264883.
And most importantly, this prevents reports of XXE vulnerabilities. As far as I can tell, you only use XML to parse trusted configuration file, which makes all those reports moot, yet you had to harden your parsers for some reason… Using Commons Secure XML, you can keep your XML code as simple as possible and at the same time reject all XXE reports. |
| DocumentBuilderFactory dbf = SecureDocumentBuilderFactory.newNSInstance(); | ||
| dbf.setNamespaceAware(true); | ||
|
|
||
| DocumentBuilder db = dbf.newDocumentBuilder(); | ||
| Document doc = db.parse(configToMonitor.getInputStream()); |
There was a problem hiding this comment.
What about upgrading to 1.1.0? All this could collapse to:
Document doc = SecureDocumentBuilderFactory.newNSDocumentBuilder().parse(configToMonitor.getInputStream());There was a problem hiding this comment.
Version 1.1.0 will be available tomorrow evening after 11 PM EDT. I will update the PR then, or create a new one.
| DocumentBuilder builder = XmlFactories.getSafeDocumentBuilderFactory().newDocumentBuilder(); | ||
| DocumentBuilder builder = SecureDocumentBuilderFactory.newNSInstance().newDocumentBuilder(); | ||
| Element docElem = builder.parse(src).getDocumentElement(); | ||
|
|
||
| XPath xpath = XPathFactory.newInstance().newXPath(); | ||
| XPath xpath = SecureXPathFactory.newInstance().newXPath(); | ||
| Attr brokerNameAttr = (Attr) xpath.evaluate(DEFAULT_BROKERNAME_XPATH, docElem, XPathConstants.NODE); |
There was a problem hiding this comment.
This will create a problem with namespaces: the XPath used is /beans/broker/@brokerName, but both beans and broker have a namespace, so the XPath will not find anything with a namespace sensitive parser.
I see a couple of solutions:
-
Use
newInstance()instead ofnewNSInstance(), but this means this path can not upgrade tonewNSDocumentBuilder(). -
Change the XPath expression to
/*[local-name()='beans'/*[local-name()='broker']/@brokerName. -
Or use DOM to find the attribute:
Element brokerElement = (Element) docElem.getElementsByTagNameNS("*", "broker").item(0); Attr brokerNameAttr = brokerElement.getAttributeNodeNS(null, "brokerName");
There was a problem hiding this comment.
@ppkarwasz I implemented your suggestion 2 in commit d64bcfd.
I like the XPath approach with namespaces because it is more precise IMO.
There was a problem hiding this comment.
Unless I am mistaken, all ActiveMQ configurations need to use namespaces, otherwise Spring will not accept them. Therefore you can also set a NamespaceContext on the XPath (there is a SimpleNamespaceContext in spring-core if you don't want to create your own), bind the namespaces and use something like /b:beans/a:broker/@brokerName.
There was a problem hiding this comment.
Hm, that may be the case but it feels like we are entering clean up territory instead of migrating to Commons Secure XML. I'd rather leave that one for the AMQ team and not make this PR more complicated.
Remove setNamespaceAware() no longer needed with SecureDocumentBuilderFactory.newNSInstance().
Spring imports the XML namespace without a schema location. Preload it so the secure resolver does not return an empty document.
Implement the suggestion in apache#2635 (review)
Harden XML calls with Apache Commons Secure XML
CC @ppkarwasz
See also: