Skip to content

Commit 66161f8

Browse files
committed
Fix SchemaFactory configuration of XML validator
Signed-off-by: nscuro <[email protected]>
1 parent 1d9ecdb commit 66161f8

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Maven Usage
2121
<dependency>
2222
<groupId>org.cyclonedx</groupId>
2323
<artifactId>cyclonedx-core-java</artifactId>
24-
<version>10.1.0</version>
24+
<version>11.0.1</version>
2525
</dependency>
2626
```
2727

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<groupId>org.cyclonedx</groupId>
2424
<artifactId>cyclonedx-core-java</artifactId>
2525
<packaging>jar</packaging>
26-
<version>11.1.0-SNAPSHOT</version>
26+
<version>11.0.1-SNAPSHOT</version>
2727

2828
<name>CycloneDX Core (Java)</name>
2929
<description>The CycloneDX core module provides a model representation of the BOM along with utilities to assist in creating, parsing, and validating BOMs.</description>

src/main/java/org/cyclonedx/CycloneDxSchema.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ private Schema getXmlSchema16() throws SAXException {
271271

272272
public Schema getXmlSchema(InputStream... inputStreams) throws SAXException {
273273
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
274+
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
275+
schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
274276
final Source[] schemaFiles = new Source[inputStreams.length];
275277
for (int i = 0; i < inputStreams.length; i++) {
276278
schemaFiles[i] = new StreamSource(inputStreams[i]);

src/test/java/org/cyclonedx/parsers/XmlParserTest.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
*/
1919
package org.cyclonedx.parsers;
2020

21+
import org.apache.commons.io.IOUtils;
2122
import org.cyclonedx.Version;
2223
import org.cyclonedx.model.Bom;
2324
import org.cyclonedx.model.Component;
2425
import org.cyclonedx.model.Component.Type;
2526
import org.cyclonedx.model.Dependency;
2627
import org.cyclonedx.model.ExternalReference;
27-
import org.cyclonedx.model.License;
2828
import org.cyclonedx.model.LicenseChoice;
2929
import org.cyclonedx.model.OrganizationalEntity;
3030
import org.cyclonedx.model.Pedigree;
@@ -65,14 +65,25 @@
6565
import org.cyclonedx.model.license.Acknowledgement;
6666
import org.cyclonedx.model.license.Expression;
6767
import org.junit.jupiter.api.Test;
68+
6869
import java.io.File;
70+
import java.io.InputStream;
71+
import java.net.ServerSocket;
72+
import java.net.Socket;
6973
import java.util.ArrayList;
7074
import java.util.Arrays;
7175
import java.util.List;
7276
import java.util.Objects;
77+
import java.util.concurrent.Callable;
78+
import java.util.concurrent.CountDownLatch;
79+
import java.util.concurrent.ExecutorService;
80+
import java.util.concurrent.Executors;
81+
import java.util.concurrent.TimeUnit;
82+
import java.util.concurrent.atomic.AtomicBoolean;
7383
import java.util.stream.Collectors;
7484

7585
import static org.junit.jupiter.api.Assertions.assertEquals;
86+
import static org.junit.jupiter.api.Assertions.assertFalse;
7687
import static org.junit.jupiter.api.Assertions.assertNotNull;
7788
import static org.junit.jupiter.api.Assertions.assertNull;
7889
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -746,4 +757,48 @@ public void testIssue492Regression() throws Exception {
746757
final Bom bom = getXmlBom("regression/issue492.xml");
747758
assertEquals(2, bom.getMetadata().getTools().size());
748759
}
760+
761+
@Test
762+
void validateShouldNotBeVulnerableToXxe() throws Exception {
763+
final byte[] bomBytes;
764+
try (final InputStream bomInputStream = getClass().getResourceAsStream("/security/xxe-protection.xml")) {
765+
assertNotNull(bomInputStream);
766+
bomBytes = IOUtils.toByteArray(bomInputStream);
767+
}
768+
769+
// To verify that the validation not only doesn't fail,
770+
// but also doesn't cause any unintended side effects,
771+
// open a TCP socket on the port referenced in the
772+
// XML file. Verify that once validation completes,
773+
// no connection attempt has been made.
774+
775+
final CountDownLatch countDownLatch = new CountDownLatch(1);
776+
final AtomicBoolean receivedConnection = new AtomicBoolean(false);
777+
778+
final ExecutorService executor = Executors.newSingleThreadExecutor();
779+
try (final ServerSocket serverSocket = new ServerSocket(1010)) {
780+
executor.submit((Callable<Void>) () -> {
781+
countDownLatch.countDown();
782+
783+
// Blocks until either a connection is received,
784+
// or the socket is closed.
785+
final Socket socket = serverSocket.accept();
786+
receivedConnection.set(true);
787+
socket.close();
788+
return null;
789+
});
790+
791+
// Wait for the socket to be ready.
792+
countDownLatch.await();
793+
794+
final XmlParser parser = new XmlParser();
795+
parser.validate(bomBytes);
796+
} finally {
797+
executor.shutdownNow();
798+
executor.awaitTermination(3, TimeUnit.SECONDS);
799+
}
800+
801+
assertFalse(receivedConnection.get());
802+
}
803+
749804
}

0 commit comments

Comments
 (0)