From 718a428aedfff2d09faf97c6a2742ef473364866 Mon Sep 17 00:00:00 2001 From: theghost5800 Date: Fri, 5 Jun 2026 17:55:47 +0300 Subject: [PATCH] Add xml parser configurations --- ...NamespaceIgnoringHttpMessageConverter.java | 16 +++++++++++++++- ...spaceIgnoringHttpMessageConverterTest.java | 19 +++++++++++++++++++ .../web/util/xxe-billion-laughs.xml | 13 +++++++++++++ .../web/util/xxe-external-entity.xml | 10 ++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-billion-laughs.xml create mode 100644 multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-external-entity.xml diff --git a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverter.java b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverter.java index 04a7dff551..8c360f1010 100644 --- a/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverter.java +++ b/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverter.java @@ -21,12 +21,26 @@ import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; import org.xml.sax.XMLFilter; import org.xml.sax.XMLReader; public class XmlNamespaceIgnoringHttpMessageConverter implements HttpMessageConverter { - private static final SAXParserFactory SAX_PARSER_FACTORY = SAXParserFactory.newInstance(); + private static final SAXParserFactory SAX_PARSER_FACTORY = createSaxParserFactory(); + + private static SAXParserFactory createSaxParserFactory() { + SAXParserFactory factory = SAXParserFactory.newInstance(); + try { + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (SAXNotRecognizedException | SAXNotSupportedException | ParserConfigurationException e) { + throw new ExceptionInInitializerError(e); + } + return factory; + } private final Jaxb2RootElementHttpMessageConverter delegate = new Jaxb2RootElementHttpMessageConverter(); diff --git a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverterTest.java b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverterTest.java index 324131ac80..c46d58c9ad 100644 --- a/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverterTest.java +++ b/multiapps-controller-web/src/test/java/org/cloudfoundry/multiapps/controller/web/util/XmlNamespaceIgnoringHttpMessageConverterTest.java @@ -3,16 +3,21 @@ import java.io.InputStream; import java.util.stream.Stream; +import org.cloudfoundry.multiapps.common.ParsingException; import org.cloudfoundry.multiapps.common.test.Tester; import org.cloudfoundry.multiapps.common.test.Tester.Expectation; import org.cloudfoundry.multiapps.controller.web.util.bar.Bar; import org.cloudfoundry.multiapps.controller.web.util.foo.Foo; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + class XmlNamespaceIgnoringHttpMessageConverterTest { private final Tester tester = Tester.forClass(getClass()); @@ -43,6 +48,20 @@ void testReadFrom(String entityResource, Class type, Expectation expectation) tester.test(() -> converter.read(type, createHttpInputMessage(entityResource)), expectation); } + @Test + void testReadFromRejectsExternalEntityXxeAttack() { + ParsingException e = assertThrows(ParsingException.class, + () -> converter.read(Foo.class, createHttpInputMessage("xxe-external-entity.xml"))); + assertTrue(e.getCause().toString().contains("DOCTYPE is disallowed"), "Expected DOCTYPE rejection but got: " + e.getCause()); + } + + @Test + void testReadFromRejectsBillionLaughsDoSAttack() { + ParsingException e = assertThrows(ParsingException.class, + () -> converter.read(Foo.class, createHttpInputMessage("xxe-billion-laughs.xml"))); + assertTrue(e.getCause().toString().contains("DOCTYPE is disallowed"), "Expected DOCTYPE rejection but got: " + e.getCause()); + } + private HttpInputMessage createHttpInputMessage(String resource) { return new HttpInputMessage() { diff --git a/multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-billion-laughs.xml b/multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-billion-laughs.xml new file mode 100644 index 0000000000..ea62e6a8c3 --- /dev/null +++ b/multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-billion-laughs.xml @@ -0,0 +1,13 @@ + + + + + +]> + + &lol4; + property-2-value + 1000 + true + diff --git a/multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-external-entity.xml b/multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-external-entity.xml new file mode 100644 index 0000000000..10f864034f --- /dev/null +++ b/multiapps-controller-web/src/test/resources/org/cloudfoundry/multiapps/controller/web/util/xxe-external-entity.xml @@ -0,0 +1,10 @@ + + +]> + + &xxe; + property-2-value + 1000 + true +