From 29d9942d5266a4decc9804e3304bd0514c8027d4 Mon Sep 17 00:00:00 2001 From: Christine Poerschke Date: Fri, 13 Oct 2017 12:46:58 +0100 Subject: [PATCH] SOLR-11477: Disallow resolving of external entities in Lucene --- .../apache/lucene/queryparser/xml/CoreParser.java | 65 +++++++++++++++++++--- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/queryparser/src/java/org/apache/lucene/queryparser/xml/CoreParser.java b/queryparser/src/java/org/apache/lucene/queryparser/xml/CoreParser.java index 02ac8b9..ac40779 100644 --- a/queryparser/src/java/org/apache/lucene/queryparser/xml/CoreParser.java +++ b/queryparser/src/java/org/apache/lucene/queryparser/xml/CoreParser.java @@ -6,10 +6,18 @@ import org.apache.lucene.queryparser.xml.builders.*; import org.apache.lucene.search.Query; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +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 java.io.InputStream; +import java.util.Locale; /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -118,6 +126,10 @@ public class CoreParser implements QueryBuilder { queryFactory.addBuilder("SpanNot", snot); } + /** + * Parses the given stream as XML file and returns a {@link Query}. + * By default this disallows external entities for security reasons. + */ public Query parse(InputStream xmlStream) throws ParserException { return getQuery(parseXML(xmlStream).getDocumentElement()); } @@ -130,23 +142,48 @@ public class CoreParser implements QueryBuilder { filterFactory.addBuilder(nodeName, builder); } - private static Document parseXML(InputStream pXmlFile) throws ParserException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = null; + /** + * Returns a SAX {@link EntityResolver} to be used by {@link DocumentBuilder}. + * By default this returns {@link #DISALLOW_EXTERNAL_ENTITY_RESOLVER}, which disallows the + * expansion of external entities (for security reasons). To restore legacy behavior, + * override this method to return {@code null}. + */ + protected EntityResolver getEntityResolver() { + return DISALLOW_EXTERNAL_ENTITY_RESOLVER; + } + + /** + * Subclass and override to return a SAX {@link ErrorHandler} to be used by {@link DocumentBuilder}. + * By default this returns {@code null} so no error handler is used. + * This method can be used to redirect XML parse errors/warnings to a custom logger. + */ + protected ErrorHandler getErrorHandler() { + return null; + } + + private Document parseXML(InputStream pXmlFile) throws ParserException { + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setValidating(false); try { - db = dbf.newDocumentBuilder(); + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + // ignore since all implementations are required to support the + // {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature } - catch (Exception se) { - throw new ParserException("XML Parser configuration error", se); + final DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + } catch (Exception se) { + throw new ParserException("XML Parser configuration error.", se); } - org.w3c.dom.Document doc = null; try { - doc = db.parse(pXmlFile); + db.setEntityResolver(getEntityResolver()); + db.setErrorHandler(getErrorHandler()); + return db.parse(pXmlFile); } catch (Exception se) { throw new ParserException("Error parsing XML stream:" + se, se); } - return doc; } @@ -154,4 +191,14 @@ public class CoreParser implements QueryBuilder { public Query getQuery(Element e) throws ParserException { return queryFactory.getQuery(e); } + + public static final EntityResolver DISALLOW_EXTERNAL_ENTITY_RESOLVER = new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException { + throw new SAXException(String.format(Locale.ENGLISH, + "External Entity resolving unsupported: publicId=\"%s\" systemId=\"%s\"", + publicId, systemId)); + } + }; + } -- 2.13.6