From 1b8c56466427714a1881d2b6d62684668f74dee9 Mon Sep 17 00:00:00 2001 From: Yury Bakhmutski Date: Mon, 24 Oct 2016 12:24:18 +0300 Subject: [PATCH] [PPP-3506] - XXE Security Vulnerability in xml parsers --- src/main/mondrian/tui/XmlUtil.java | 7 +- .../util/XmlParserFactoryProducer.java | 102 ++++++++++++++++++ src/main/mondrian/xmla/XmlaConstants.java | 28 +++-- src/main/mondrian/xmla/XmlaUtil.java | 7 +- .../xmla/impl/DefaultXmlaServlet.java | 14 ++- 5 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 src/main/mondrian/util/XmlParserFactoryProducer.java diff --git a/src/main/mondrian/tui/XmlUtil.java b/src/main/mondrian/tui/XmlUtil.java index 897d41ca03..621fb14de5 100644 --- a/src/main/mondrian/tui/XmlUtil.java +++ b/src/main/mondrian/tui/XmlUtil.java @@ -9,6 +9,7 @@ package mondrian.tui; import mondrian.olap.Util; +import mondrian.util.XmlParserFactoryProducer; import org.apache.xerces.dom.DocumentImpl; import org.apache.xerces.impl.Constants; @@ -851,7 +852,8 @@ public static Node transform( TransformerConfigurationException, TransformerException { - DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory dfactory = + XmlParserFactoryProducer.createSecureDocBuilderFactory(); dfactory.setNamespaceAware(true); DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); @@ -901,7 +903,8 @@ public static Node transform( TransformerConfigurationException, TransformerException { - DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory dfactory = + XmlParserFactoryProducer.createSecureDocBuilderFactory(); dfactory.setNamespaceAware(true); DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); diff --git a/src/main/mondrian/util/XmlParserFactoryProducer.java b/src/main/mondrian/util/XmlParserFactoryProducer.java new file mode 100644 index 0000000000..89750986c7 --- /dev/null +++ b/src/main/mondrian/util/XmlParserFactoryProducer.java @@ -0,0 +1,102 @@ +/* +// This software is subject to the terms of the Eclipse Public License v1.0 +// Agreement, available at the following URL: +// http://www.eclipse.org/legal/epl-v10.html. +// You must accept the terms of that agreement to use this software. +// +// Copyright (C) 2003-2005 Julian Hyde +// Copyright (C) 2005-2016 Pentaho +// All Rights Reserved. +*/ +package mondrian.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.dom4j.io.SAXReader; +import org.xml.sax.EntityResolver; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; + +/** + * Class was created to prevent XXE Security Vulnerabilities + * http://jira.pentaho.com/browse/PPP-3506 + * + * Created by Yury_Bakhmutski on 10/21/2016. + */ +public class XmlParserFactoryProducer { + private static final Log logger = + LogFactory.getLog(XmlParserFactoryProducer.class); + /** + * Creates an instance of {@link DocumentBuilderFactory} class + * with enabled {@link XMLConstants#FEATURE_SECURE_PROCESSING} property. + * Enabling this feature prevents from some XXE attacks (e.g. XML bomb) + * See PPP-3506 for more details. + * + * @throws ParserConfigurationException if feature can't be enabled + * + */ + public static DocumentBuilderFactory createSecureDocBuilderFactory() + throws ParserConfigurationException + { + DocumentBuilderFactory docBuilderFactory = + DocumentBuilderFactory.newInstance(); + docBuilderFactory.setFeature( + XMLConstants.FEATURE_SECURE_PROCESSING, true); + docBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + + return docBuilderFactory; + } + + /** + * Creates an instance of {@link SAXParserFactory} class with enabled {@link XMLConstants#FEATURE_SECURE_PROCESSING} property. + * Enabling this feature prevents from some XXE attacks (e.g. XML bomb) + * + * @throws ParserConfigurationException if a parser cannot + * be created which satisfies the requested configuration. + * + * @throws SAXNotRecognizedException When the underlying XMLReader does + * not recognize the property name. + * + * @throws SAXNotSupportedException When the underlying XMLReader + * recognizes the property name but doesn't support the + * property. + */ + public static SAXParserFactory createSecureSAXParserFactory() + throws SAXNotSupportedException, SAXNotRecognizedException, + ParserConfigurationException + { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 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); + return factory; + } + + public static SAXReader getSAXReader(final EntityResolver resolver) { + SAXReader reader = new SAXReader(); + if (resolver != null) { + reader.setEntityResolver(resolver); + } + try { + reader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + reader.setFeature("http://xml.org/sax/features/external-general-entities", false); + reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } catch (SAXException e) { + logger.error("Some parser properties are not supported."); + } + reader.setIncludeExternalDTDDeclarations(false); + reader.setIncludeInternalDTDDeclarations(false); + return reader; + } +} + +// End XmlParserFactoryProducer.java diff --git a/src/main/mondrian/xmla/XmlaConstants.java b/src/main/mondrian/xmla/XmlaConstants.java index 2974df5092..0ebf9a0b45 100644 --- a/src/main/mondrian/xmla/XmlaConstants.java +++ b/src/main/mondrian/xmla/XmlaConstants.java @@ -1,12 +1,13 @@ /* -* This software is subject to the terms of the Eclipse Public License v1.0 -* Agreement, available at the following URL: -* http://www.eclipse.org/legal/epl-v10.html. -* You must accept the terms of that agreement to use this software. -* -* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. +// This software is subject to the terms of the Eclipse Public License v1.0 +// Agreement, available at the following URL: +// http://www.eclipse.org/legal/epl-v10.html. +// You must accept the terms of that agreement to use this software. +// +// Copyright (C) 2001-2005 Julian Hyde +// Copyright (C) 2005-2016 Pentaho and others +// All Rights Reserved. */ - package mondrian.xmla; /** @@ -50,12 +51,12 @@ public interface XmlaConstants { public static final String SOAP_PREFIX = "SOAP-ENV"; - /* + /** * Soap Header mustUnderstand attribute name. */ public static final String SOAP_MUST_UNDERSTAND_ATTR = "mustUnderstand"; - /* + /** * Soap XMLA Header elements and attribute names. */ public static final String XMLA_BEGIN_SESSION = "BeginSession"; @@ -64,7 +65,7 @@ public interface XmlaConstants { public static final String XMLA_SESSION_ID = "SessionId"; public static final String XMLA_SECURITY = "Security"; - /* + /** * Names of context keys known by both callbacks and Mondrian code. */ // context key for role name storage @@ -120,6 +121,13 @@ public interface XmlaConstants { public static final String FAULT_FC_PREFIX = "Mondrian"; public static final String FAULT_FS_PREFIX = "The Mondrian XML: "; + ///////////////////////////////////////////////////////////////////////// + // Servlet Initialization Error : SIE + ///////////////////////////////////////////////////////////////////////// + public static final String SIE_REQUEST_STATE_CODE = "00SIEA01"; + public static final String SIE_REQUEST_STATE_FAULT_FS = + "Servlet initialization error"; + ///////////////////////////////////////////////////////////////////////// // Unmarshall Soap Message : USM ///////////////////////////////////////////////////////////////////////// diff --git a/src/main/mondrian/xmla/XmlaUtil.java b/src/main/mondrian/xmla/XmlaUtil.java index ef623e6898..fa15dae5d4 100644 --- a/src/main/mondrian/xmla/XmlaUtil.java +++ b/src/main/mondrian/xmla/XmlaUtil.java @@ -5,14 +5,14 @@ // You must accept the terms of that agreement to use this software. // // Copyright (C) 2003-2005 Julian Hyde -// Copyright (C) 2005-2011 Pentaho +// Copyright (C) 2005-2016 Pentaho // All Rights Reserved. */ - package mondrian.xmla; import mondrian.olap.MondrianException; import mondrian.olap.Util; +import mondrian.util.XmlParserFactoryProducer; import mondrian.xmla.impl.DefaultXmlaResponse; import org.olap4j.OlapConnection; @@ -161,10 +161,11 @@ private static Element _2Element(InputSource source) { try { DocumentBuilderFactory factory = - DocumentBuilderFactory.newInstance(); + XmlParserFactoryProducer.createSecureDocBuilderFactory(); factory.setIgnoringElementContentWhitespace(true); factory.setIgnoringComments(true); factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(source); return doc.getDocumentElement(); diff --git a/src/main/mondrian/xmla/impl/DefaultXmlaServlet.java b/src/main/mondrian/xmla/impl/DefaultXmlaServlet.java index df2beb7a8e..96454774b3 100644 --- a/src/main/mondrian/xmla/impl/DefaultXmlaServlet.java +++ b/src/main/mondrian/xmla/impl/DefaultXmlaServlet.java @@ -5,11 +5,12 @@ // You must accept the terms of that agreement to use this software. // // Copyright (C) 2001-2005 Julian Hyde -// Copyright (C) 2005-2014 Pentaho and others +// Copyright (C) 2005-2016 Pentaho and others // All Rights Reserved. */ package mondrian.xmla.impl; +import mondrian.util.XmlParserFactoryProducer; import mondrian.xmla.*; import org.olap4j.impl.Olap4jUtil; @@ -65,7 +66,16 @@ public void init(ServletConfig servletConfig) throws ServletException { } protected static DocumentBuilderFactory getDocumentBuilderFactory() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory factory; + try { + factory = XmlParserFactoryProducer.createSecureDocBuilderFactory(); + } catch (ParserConfigurationException ex) { + throw new XmlaException( + SERVER_FAULT_FC, + SIE_REQUEST_STATE_CODE, + SIE_REQUEST_STATE_FAULT_FS, + ex); + } factory.setIgnoringComments(true); factory.setIgnoringElementContentWhitespace(true); factory.setNamespaceAware(true);