diff --git a/library/src/main/java/org/mustangproject/XMLTools.java b/library/src/main/java/org/mustangproject/XMLTools.java index 42e533eb..e7d09fca 100644 --- a/library/src/main/java/org/mustangproject/XMLTools.java +++ b/library/src/main/java/org/mustangproject/XMLTools.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.RoundingMode; +import java.net.URL; import java.text.SimpleDateFormat; import java.util.Date; @@ -11,11 +12,19 @@ import org.apache.commons.io.IOUtils; import org.dom4j.io.XMLWriter; import org.mustangproject.ZUGFeRD.ZUGFeRDDateFormat; import org.w3c.dom.Node; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; public class XMLTools extends XMLWriter { @Override @@ -28,29 +37,85 @@ public class XMLTools extends XMLWriter { return super.escapeElementEntities(s); } - public static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException { + public static DocumentBuilder getDocumentBuilder(boolean namespaceAware) throws ParserConfigurationException { final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //REDHAT //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf - dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + try { + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + // ignore + } + try { + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + } catch (IllegalArgumentException e) { + // ignore + } + try { + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + } catch (IllegalArgumentException e) { + // ignore + } //OWASP //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html - dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); - dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + try { + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } catch (ParserConfigurationException e) { + // ignore + } + try { + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + } catch (ParserConfigurationException e) { + // ignore + } + try { + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (ParserConfigurationException e) { + // ignore + } + try { // Disable external DTDs as well - dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } catch (ParserConfigurationException e) { + // ignore + } // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" dbf.setXIncludeAware(false); dbf.setExpandEntityReferences(false); - dbf.setNamespaceAware(true); + dbf.setNamespaceAware(namespaceAware); return dbf.newDocumentBuilder(); - } + public static Validator getValidator(URL schemaFile) throws SAXException + { + SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + try { + schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + } catch (SAXNotSupportedException | SAXNotRecognizedException e) { + // ignore + } + Schema schema = schemaFactory.newSchema(schemaFile); + + Validator validator = schema.newValidator(); + try { + validator.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (SAXNotSupportedException | SAXNotRecognizedException e) { + // ignore + } + return validator; + } + + public static TransformerFactory getTransformerFactory() + { + TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl(); + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (TransformerConfigurationException e) { + // ignore + } + return factory; + } public static String nDigitFormat(BigDecimal value, int scale) { /* diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java index 17c3e1ea..53218d70 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ValidationLogVisualizer.java @@ -15,6 +15,7 @@ import org.apache.fop.configuration.ConfigurationException; import org.apache.fop.configuration.DefaultConfigurationBuilder; import org.apache.xmlgraphics.util.MimeConstants; import org.mustangproject.ClasspathResolverURIAdapter; +import org.mustangproject.XMLTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,8 +43,7 @@ public class ValidationLogVisualizer { public ValidationLogVisualizer() { - mFactory = new net.sf.saxon.TransformerFactoryImpl(); - // fact = TransformerFactory.newInstance(); + mFactory = XMLTools.getTransformerFactory(); mFactory.setURIResolver(new ValidationLogVisualizer.ClasspathResourceURIResolver()); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/XMLUpgrader.java b/library/src/main/java/org/mustangproject/ZUGFeRD/XMLUpgrader.java index cf71f2b7..4153938f 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/XMLUpgrader.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/XMLUpgrader.java @@ -16,6 +16,8 @@ import javax.xml.transform.URIResolver; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.mustangproject.XMLTools; + /*** * Uses a XSLT transformation to upgrade @@ -31,8 +33,7 @@ public class XMLUpgrader { private Templates mXsltTemplate = null; public XMLUpgrader() { - mFactory = new net.sf.saxon.TransformerFactoryImpl(); - //fact = TransformerFactory.newInstance(); + mFactory = XMLTools.getTransformerFactory(); mFactory.setURIResolver(new ClasspathResourceURIResolver()); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 07336564..b3248507 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -18,9 +18,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; -import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; @@ -341,7 +339,7 @@ public class ZUGFeRDInvoiceImporter { final ByteArrayInputStream is = new ByteArrayInputStream(rawXML); /// is.skip(guessBOMSize(is)); try { - DocumentBuilder builder = XMLTools.getDocumentBuilder(); + DocumentBuilder builder = XMLTools.getDocumentBuilder(true); document = builder.parse(is); } catch (Exception e) { @@ -356,7 +354,7 @@ public class ZUGFeRDInvoiceImporter { final ByteArrayInputStream is = new ByteArrayInputStream(rawXML); /// is.skip(guessBOMSize(is)); - DocumentBuilder builder = XMLTools.getDocumentBuilder(); + DocumentBuilder builder = XMLTools.getDocumentBuilder(true); if (canParse()) { document = builder.parse(is); if (parseAutomatically) { diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index ec699252..3e663c28 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -32,6 +32,7 @@ import org.apache.fop.configuration.DefaultConfigurationBuilder; import org.apache.xmlgraphics.util.MimeConstants; import org.mustangproject.ClasspathResolverURIAdapter; import org.mustangproject.EStandard; +import org.mustangproject.XMLTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -39,7 +40,6 @@ import org.w3c.dom.Element; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.*; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; @@ -47,8 +47,6 @@ import javax.xml.transform.stream.StreamSource; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -85,8 +83,7 @@ public class ZUGFeRDVisualizer { private Templates mXsltZF1HTMLTemplate = null; public ZUGFeRDVisualizer() { - mFactory = new net.sf.saxon.TransformerFactoryImpl(); - // fact = TransformerFactory.newInstance(); + mFactory = XMLTools.getTransformerFactory(); mFactory.setURIResolver(new ClasspathResourceURIResolver()); } @@ -104,40 +101,8 @@ public class ZUGFeRDVisualizer { String ublCreditNoteSignature = "CreditNote"; String cioSignature = "SCRDMCCBDACIOMessageStructure"; - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - //REDHAT - //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf - dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - try - { - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - } - catch (IllegalArgumentException e) - { - LOGGER.warn("Property: \"Access external DTD\" not supported."); - } - try - { - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); - } - catch (IllegalArgumentException e) - { - LOGGER.warn("Property: \"Access external schema\" not supported."); - } - - //OWASP - //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html - dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); - dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - // Disable external DTDs as well - dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" - dbf.setXIncludeAware(false); - dbf.setExpandEntityReferences(false); - dbf.setNamespaceAware(true); try { - DocumentBuilder db = dbf.newDocumentBuilder(); + DocumentBuilder db = XMLTools.getDocumentBuilder(true); Document doc = db.parse(new InputSource(fis)); Element root = doc.getDocumentElement(); if (root.getLocalName().equals(zf1Signature)) { diff --git a/validator/src/main/java/org/mustangproject/validator/PDFValidator.java b/validator/src/main/java/org/mustangproject/validator/PDFValidator.java index cc548951..75f85981 100644 --- a/validator/src/main/java/org/mustangproject/validator/PDFValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/PDFValidator.java @@ -14,7 +14,6 @@ import java.util.HashMap; import java.util.Set; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; @@ -23,6 +22,7 @@ import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.mustangproject.util.ByteArraySearcher; +import org.mustangproject.XMLTools; import org.mustangproject.ZUGFeRD.ZUGFeRDImporter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -142,12 +142,7 @@ public class PDFValidator extends Validator { * 1.0 */ try { - final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" - factory.setXIncludeAware(false); - - final DocumentBuilder builder = factory.newDocumentBuilder(); + final DocumentBuilder builder = XMLTools.getDocumentBuilder(false); final InputSource is = new InputSource(new StringReader(xmp)); docXMP = builder.parse(is); diff --git a/validator/src/main/java/org/mustangproject/validator/Validator.java b/validator/src/main/java/org/mustangproject/validator/Validator.java index 513e996f..c4484b71 100644 --- a/validator/src/main/java/org/mustangproject/validator/Validator.java +++ b/validator/src/main/java/org/mustangproject/validator/Validator.java @@ -7,9 +7,8 @@ import java.net.URL; import javax.xml.XMLConstants; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; +import org.mustangproject.XMLTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; @@ -59,11 +58,8 @@ public abstract class Validator { protected void validateSchema(byte[] xmlRawData, String schemaPath, int section, EPart part) throws IrrecoverableValidationError { URL schemaFile = Thread.currentThread().getContextClassLoader().getResource("schema/" + schemaPath); Source xmlData = new StreamSource(new ByteArrayInputStream(xmlRawData)); - SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); try { - schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - Schema schema = schemaFactory.newSchema(schemaFile); - javax.xml.validation.Validator validator = schema.newValidator(); + javax.xml.validation.Validator validator = XMLTools.getValidator(schemaFile); validator.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); validator.validate(xmlData); } catch (SAXException e) { diff --git a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java index 61565f61..ad787203 100644 --- a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java @@ -13,9 +13,7 @@ import java.text.ParseException; import java.util.Calendar; import java.util.Set; -import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.stream.StreamSource; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; @@ -156,26 +154,7 @@ public class XMLValidator extends Validator { * */ - final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - //REDHAT - //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf - dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); - - //OWASP - //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html - dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); - dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - // Disable external DTDs as well - dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" - dbf.setXIncludeAware(false); - dbf.setExpandEntityReferences(false); - dbf.setNamespaceAware(true); - - final DocumentBuilder db = dbf.newDocumentBuilder(); + final DocumentBuilder db = XMLTools.getDocumentBuilder(true); final InputSource is = new InputSource(new StringReader(zfXML)); final Document doc = db.parse(is); diff --git a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java index 71bbdab3..e6a319a4 100644 --- a/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/ZUGFeRDValidator.java @@ -17,9 +17,7 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; -import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.io.IOUtils; import org.dom4j.DocumentException; @@ -143,24 +141,7 @@ public class ZUGFeRDValidator { boolean isXML = false; String xmlAsString = null; try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - //REDHAT - //https://www.blackhat.com/docs/us-15/materials/us-15-Wang-FileCry-The-New-Age-Of-XXE-java-wp.pdf - dbf.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true); - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); - - //OWASP - //https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html - dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - // Disable external DTDs as well - dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks" - dbf.setXIncludeAware(false); - dbf.setExpandEntityReferences(false); - dbf.setNamespaceAware(true); - DocumentBuilder db = dbf.newDocumentBuilder(); + DocumentBuilder db = XMLTools.getDocumentBuilder(true); content = XMLTools.removeBOM(content); xmlAsString = new String(content, StandardCharsets.UTF_8);