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