Visitar URL original
Harden XML with Commons Secure XML by garydgregory · Pull Request #2635 · apache/activemq · GitHub
Skip to content

Harden XML with Commons Secure XML - #2635

Open
garydgregory wants to merge 6 commits into
apache:mainfrom
garydgregory:main_commons_secure_xml
Open

garydgregory wants to merge 6 commits into
apache:mainfrom
garydgregory:main_commons_secure_xml

Conversation

@garydgregory

@garydgregory garydgregory commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

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.
@mattrpav

mattrpav commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Hi @garydgregory

thank you for the PR. Can you share a bit what the advantages are of using this library?

@garydgregory

Copy link
Copy Markdown
Member Author

Hi @mattrpav CC @ppkarwasz

Commons Secure XML is a tiny library that:

  • Prevents XXE Attacks: It disables external entity resolution, blocking XML External Entity (XXE) vulnerabilities that lead to data exposure.
  • Prevents Billion Laughs Attacks: It restricts recursive entity expansion, preventing denial-of-service (DoS) attempts.
  • Configures standard XML parsers with safe, restrictive settings out of the box.
  • Eliminates manual, error-prone security configuration of DocumentBuilderFactory, SAXParserFactory, TransformerFactory, and so on

HTH!

@garydgregory

Copy link
Copy Markdown
Member Author

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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#loadConfiguration uses a namepace-aware parser and retrieves the broker element via:
    doc.getElementsByTagNameNS("*","broker").item(0);
  • CreateCommand#copyActivemqConf uses a namespace-unaware parser and retrieves the same broker element via XPath.

I think both could use a namespace-aware parser

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented @ppkarwasz 's suggestion in commit 6264883.

@ppkarwasz

Copy link
Copy Markdown
Member
  • Prevents XXE Attacks: It disables external entity resolution, blocking XML External Entity (XXE) vulnerabilities that lead to data exposure.

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.

@garydgregory garydgregory changed the title Main commons secure xml Harden XML with Commons Secure XML Oct 4, 2026
Comment on lines +184 to 188
DocumentBuilderFactory dbf = SecureDocumentBuilderFactory.newNSInstance();
dbf.setNamespaceAware(true);

DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(configToMonitor.getInputStream());

@ppkarwasz ppkarwasz Oct 4, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about upgrading to 1.1.0? All this could collapse to:

Document doc = SecureDocumentBuilderFactory.newNSDocumentBuilder().parse(configToMonitor.getInputStream());

@garydgregory garydgregory Oct 4, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version 1.1.0 will be available tomorrow evening after 11 PM EDT. I will update the PR then, or create a new one.

Comment on lines -161 to 167
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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. Use newInstance() instead of newNSInstance(), but this means this path can not upgrade to newNSDocumentBuilder().

  2. Change the XPath expression to /*[local-name()='beans'/*[local-name()='broker']/@brokerName.

  3. Or use DOM to find the attribute:

    Element brokerElement = (Element) docElem.getElementsByTagNameNS("*", "broker").item(0);
    Attr brokerNameAttr = brokerElement.getAttributeNodeNS(null, "brokerName");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppkarwasz I implemented your suggestion 2 in commit d64bcfd.
I like the XPath approach with namespaces because it is more precise IMO.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

3 participants