From c2bf446292f169e9560b5b366c6495bb3a41a531 Mon Sep 17 00:00:00 2001 From: "Matteo Franci a.k.a. Fugerit" Date: Wed, 9 Apr 2025 22:03:53 +0200 Subject: [PATCH 1/4] XMLFactorySAX secure version #87 --- .../java/core/xml/sax/XMLFactorySAX.java | 45 +++++++++++++++---- .../java/core/xml/sax/TestXmlFactorySAX.java | 8 ++++ 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java index fe2223f0..543fbf7d 100644 --- a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java +++ b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java @@ -29,6 +29,10 @@ public XMLValidator newXMLValidator(EntityResolver er) throws XMLException { public static SAXParser makeSAXParser(boolean val, boolean nsa) throws XMLException { return (newInstance(val, nsa).newSAXParser()); } + + public static SAXParser makeSAXParserSecure(boolean val, boolean nsa) throws XMLException { + return (newInstanceSecure(val, nsa).newSAXParser()); + } public SAXParser newSAXParser() throws XMLException { return SafeFunction.getEx( () -> this.factory.newSAXParser(), XMLException.CONVERT_FUN ); @@ -36,19 +40,44 @@ public SAXParser newSAXParser() throws XMLException { public static XMLFactorySAX newInstance() throws XMLException { return newInstance(false, false); - } + } + + public static XMLFactorySAX newInstanceSecure() throws XMLException { + return newInstanceSecure(false); + } public static XMLFactorySAX newInstance(boolean validating) throws XMLException { return newInstance(validating, false); } - + + public static XMLFactorySAX newInstanceSecure(boolean validating) throws XMLException { + return newInstanceSecure(validating, false); + } + + public static SAXParserFactory disableExternalEntity(SAXParserFactory saxFac) throws XMLException { + return XMLException.get( () -> { + saxFac.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + saxFac.setFeature("http://xml.org/sax/features/external-general-entities", false); + saxFac.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + saxFac.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + saxFac.setXIncludeAware(false); + return saxFac; + } ); + } + + private static SAXParserFactory init( boolean validating, boolean namespaceAware ) { + SAXParserFactory saxFac = SAXParserFactory.newInstance(); + saxFac.setValidating(validating); + saxFac.setNamespaceAware(namespaceAware); + return saxFac; + } + + public static XMLFactorySAX newInstanceSecure(boolean validating, boolean namespaceAware) throws XMLException { + return new XMLFactorySAX( disableExternalEntity( init( validating, namespaceAware ) ) ); + } + public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAware) throws XMLException { - return XMLException.get( () -> { - SAXParserFactory saxFac = SAXParserFactory.newInstance(); - saxFac.setValidating(validating); - saxFac.setNamespaceAware(namespaceAware); - return new XMLFactorySAX(saxFac); - } ); + return new XMLFactorySAX( init( validating, namespaceAware ) ); } public void setValidating(boolean val) { diff --git a/fj-core/src/test/java/test/org/fugerit/java/core/xml/sax/TestXmlFactorySAX.java b/fj-core/src/test/java/test/org/fugerit/java/core/xml/sax/TestXmlFactorySAX.java index 087fdd5c..b156e9a2 100644 --- a/fj-core/src/test/java/test/org/fugerit/java/core/xml/sax/TestXmlFactorySAX.java +++ b/fj-core/src/test/java/test/org/fugerit/java/core/xml/sax/TestXmlFactorySAX.java @@ -28,6 +28,14 @@ public void test1() throws XMLException { boolean ok = this.worker( XMLFactorySAX.newInstance() ); Assert.assertTrue(ok); } + + @Test + public void testSecure() throws XMLException { + Assert.assertNotNull( XMLFactorySAX.makeSAXParserSecure( true, true ) ); + Assert.assertTrue( this.worker( XMLFactorySAX.newInstanceSecure() ) ); + Assert.assertTrue( this.worker( XMLFactorySAX.newInstanceSecure( true ) ) ); + Assert.assertTrue( this.worker( XMLFactorySAX.newInstanceSecure( true, true ) ) ); + } @Test public void test2() throws XMLException { From 8f6df4274dde1d16e5d86745da260e6001434035 Mon Sep 17 00:00:00 2001 From: "Matteo Franci a.k.a. Fugerit" Date: Wed, 9 Apr 2025 22:12:52 +0200 Subject: [PATCH 2/4] XMLFactorySAX secure version #87 --- CHANGELOG.md | 4 ++++ .../java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4cbaf76..84185a7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- XMLFactorySAX.newInstanceSecure() disabling external entities + ### Changed - Added 'ubuntu-24.04-arm' runner to compatibility workdlow diff --git a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java index 543fbf7d..16e7765e 100644 --- a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java +++ b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java @@ -76,7 +76,7 @@ public static XMLFactorySAX newInstanceSecure(boolean validating, boolean namesp return new XMLFactorySAX( disableExternalEntity( init( validating, namespaceAware ) ) ); } - public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAware) throws XMLException { + public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAware) { return new XMLFactorySAX( init( validating, namespaceAware ) ); } From 9fdf79611a8dd031b122e2d1b4fe56c766517f15 Mon Sep 17 00:00:00 2001 From: "Matteo Franci a.k.a. Fugerit" Date: Wed, 9 Apr 2025 22:22:04 +0200 Subject: [PATCH 3/4] Fix sonar issues #87 --- .../java/core/xml/sax/XMLFactorySAX.java | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java index 16e7765e..7d3d0252 100644 --- a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java +++ b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java @@ -54,30 +54,28 @@ public static XMLFactorySAX newInstanceSecure(boolean validating) throws XMLExce return newInstanceSecure(validating, false); } - public static SAXParserFactory disableExternalEntity(SAXParserFactory saxFac) throws XMLException { - return XMLException.get( () -> { - saxFac.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - saxFac.setFeature("http://xml.org/sax/features/external-general-entities", false); - saxFac.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - saxFac.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - saxFac.setXIncludeAware(false); - return saxFac; - } ); - } - - private static SAXParserFactory init( boolean validating, boolean namespaceAware ) { - SAXParserFactory saxFac = SAXParserFactory.newInstance(); - saxFac.setValidating(validating); - saxFac.setNamespaceAware(namespaceAware); - return saxFac; + public static XMLFactorySAX newInstanceSecure(boolean validating, boolean namespaceAware) throws XMLException { + return newInstance( validating, namespaceAware, Boolean.TRUE ); } - public static XMLFactorySAX newInstanceSecure(boolean validating, boolean namespaceAware) throws XMLException { - return new XMLFactorySAX( disableExternalEntity( init( validating, namespaceAware ) ) ); + public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAware) throws XMLException { + return newInstance( validating, namespaceAware, Boolean.FALSE ); } - public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAware) { - return new XMLFactorySAX( init( validating, namespaceAware ) ); + public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAware, boolean secure) throws XMLException { + return XMLException.get( () -> { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setValidating(validating); + factory.setNamespaceAware(namespaceAware); + if ( secure ) { + 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); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + factory.setXIncludeAware(false); + } + return new XMLFactorySAX( factory ); + } ); } public void setValidating(boolean val) { From e1cd6fab4bf1da8017d778dba79d4b406497453f Mon Sep 17 00:00:00 2001 From: "Matteo Franci a.k.a. Fugerit" Date: Wed, 9 Apr 2025 23:01:15 +0200 Subject: [PATCH 4/4] XMLFactorySAX javaodc #87 --- .../fugerit/java/core/xml/sax/XMLFactorySAX.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java index 7d3d0252..da4dedc6 100644 --- a/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java +++ b/fj-core/src/main/java/org/fugerit/java/core/xml/sax/XMLFactorySAX.java @@ -62,6 +62,22 @@ public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAwa return newInstance( validating, namespaceAware, Boolean.FALSE ); } + /** + * Creates a new XMLFactorySAX wrapping a javax.xml.parsers.SAXParserFactory + * + * if the secure flag is set, the external entities will be disabled : + * + 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); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + * + * @param validating to set the XMLFactorySAX as validating + * @param namespaceAware to set the XMLFactorySAX as namespaceAware + * @param secure to set the XMLFactorySAX as secure (external entities disabled) + * @return the new configured XMLFactorySAX + * @throws XMLException in case any issue arise + */ public static XMLFactorySAX newInstance(boolean validating, boolean namespaceAware, boolean secure) throws XMLException { return XMLException.get( () -> { SAXParserFactory factory = SAXParserFactory.newInstance();