-
Notifications
You must be signed in to change notification settings - Fork 860
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request from GHSA-37xm-4h3m-5w3v
* refactor: Clean up whitespace in existing PgSQLXMLTest * fix: Fix XXE vulnerability in PgSQLXML by disabling external access and doctypes Fixes XXE vulnerability by defaulting to disabling external access and doc types. The legacy insecure behavior can be restored via the new connection property xmlFactoryFactory with a value of LEGACY_INSECURE. Alternatively, a custom class name can be specified that implements org.postgresql.xml.PGXmlFactoryFactory and takes a no argument constructor. * fix: Add missing getter and setter for XML_FACTORY_FACTORY to BasicDataSource
- Loading branch information
Showing
11 changed files
with
453 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
140 changes: 140 additions & 0 deletions
140
pgjdbc/src/main/java/org/postgresql/xml/DefaultPGXmlFactoryFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
/* | ||
* Copyright (c) 2020, PostgreSQL Global Development Group | ||
* See the LICENSE file in the project root for more information. | ||
*/ | ||
|
||
package org.postgresql.xml; | ||
|
||
import org.xml.sax.SAXException; | ||
import org.xml.sax.XMLReader; | ||
import org.xml.sax.helpers.XMLReaderFactory; | ||
|
||
import javax.xml.XMLConstants; | ||
import javax.xml.parsers.DocumentBuilder; | ||
import javax.xml.parsers.DocumentBuilderFactory; | ||
import javax.xml.parsers.ParserConfigurationException; | ||
import javax.xml.stream.XMLInputFactory; | ||
import javax.xml.stream.XMLOutputFactory; | ||
import javax.xml.transform.TransformerFactory; | ||
import javax.xml.transform.sax.SAXTransformerFactory; | ||
|
||
/** | ||
* Default implementation of PGXmlFactoryFactory that configures each factory per OWASP recommendations. | ||
* | ||
* @see <a href="https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html">https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html</a> | ||
*/ | ||
public class DefaultPGXmlFactoryFactory implements PGXmlFactoryFactory { | ||
public static final DefaultPGXmlFactoryFactory INSTANCE = new DefaultPGXmlFactoryFactory(); | ||
|
||
private DefaultPGXmlFactoryFactory() { | ||
} | ||
|
||
private DocumentBuilderFactory getDocumentBuilderFactory() { | ||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | ||
setFactoryProperties(factory); | ||
factory.setXIncludeAware(false); | ||
factory.setExpandEntityReferences(false); | ||
return factory; | ||
} | ||
|
||
@Override | ||
public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { | ||
DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); | ||
builder.setEntityResolver(EmptyStringEntityResolver.INSTANCE); | ||
builder.setErrorHandler(NullErrorHandler.INSTANCE); | ||
return builder; | ||
} | ||
|
||
@Override | ||
public TransformerFactory newTransformerFactory() { | ||
TransformerFactory factory = TransformerFactory.newInstance(); | ||
setFactoryProperties(factory); | ||
return factory; | ||
} | ||
|
||
@Override | ||
public SAXTransformerFactory newSAXTransformerFactory() { | ||
SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); | ||
setFactoryProperties(factory); | ||
return factory; | ||
} | ||
|
||
@Override | ||
public XMLInputFactory newXMLInputFactory() { | ||
XMLInputFactory factory = XMLInputFactory.newInstance(); | ||
setPropertyQuietly(factory, XMLInputFactory.SUPPORT_DTD, false); | ||
setPropertyQuietly(factory, XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); | ||
return factory; | ||
} | ||
|
||
@Override | ||
public XMLOutputFactory newXMLOutputFactory() { | ||
XMLOutputFactory factory = XMLOutputFactory.newInstance(); | ||
return factory; | ||
} | ||
|
||
@Override | ||
public XMLReader createXMLReader() throws SAXException { | ||
XMLReader factory = XMLReaderFactory.createXMLReader(); | ||
setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", true); | ||
setFeatureQuietly(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); | ||
setFeatureQuietly(factory, "http://xml.org/sax/features/external-general-entities", false); | ||
setFeatureQuietly(factory, "http://xml.org/sax/features/external-parameter-entities", false); | ||
factory.setErrorHandler(NullErrorHandler.INSTANCE); | ||
return factory; | ||
} | ||
|
||
private static void setFeatureQuietly(Object factory, String name, boolean value) { | ||
try { | ||
if (factory instanceof DocumentBuilderFactory) { | ||
((DocumentBuilderFactory) factory).setFeature(name, value); | ||
} else if (factory instanceof TransformerFactory) { | ||
((TransformerFactory) factory).setFeature(name, value); | ||
} else if (factory instanceof XMLReader) { | ||
((XMLReader) factory).setFeature(name, value); | ||
} else { | ||
throw new Error("Invalid factory class: " + factory.getClass()); | ||
} | ||
return; | ||
} catch (Exception ignore) { | ||
} | ||
} | ||
|
||
private static void setAttributeQuietly(Object factory, String name, Object value) { | ||
try { | ||
if (factory instanceof DocumentBuilderFactory) { | ||
((DocumentBuilderFactory) factory).setAttribute(name, value); | ||
} else if (factory instanceof TransformerFactory) { | ||
((TransformerFactory) factory).setAttribute(name, value); | ||
} else { | ||
throw new Error("Invalid factory class: " + factory.getClass()); | ||
} | ||
} catch (Exception ignore) { | ||
} | ||
} | ||
|
||
private static void setFactoryProperties(Object factory) { | ||
setFeatureQuietly(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true); | ||
setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", true); | ||
setFeatureQuietly(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); | ||
setFeatureQuietly(factory, "http://xml.org/sax/features/external-general-entities", false); | ||
setFeatureQuietly(factory, "http://xml.org/sax/features/external-parameter-entities", false); | ||
// Values from XMLConstants inlined for JDK 1.6 compatibility | ||
setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalDTD", ""); | ||
setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalSchema", ""); | ||
setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", ""); | ||
} | ||
|
||
private static void setPropertyQuietly(Object factory, String name, Object value) { | ||
try { | ||
if (factory instanceof XMLReader) { | ||
((XMLReader) factory).setProperty(name, value); | ||
} else if (factory instanceof XMLInputFactory) { | ||
((XMLInputFactory) factory).setProperty(name, value); | ||
} else { | ||
throw new Error("Invalid factory class: " + factory.getClass()); | ||
} | ||
} catch (Exception ignore) { | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
pgjdbc/src/main/java/org/postgresql/xml/EmptyStringEntityResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* | ||
* Copyright (c) 2020, PostgreSQL Global Development Group | ||
* See the LICENSE file in the project root for more information. | ||
*/ | ||
|
||
package org.postgresql.xml; | ||
|
||
import org.xml.sax.EntityResolver; | ||
import org.xml.sax.InputSource; | ||
import org.xml.sax.SAXException; | ||
|
||
import java.io.IOException; | ||
import java.io.StringReader; | ||
|
||
public class EmptyStringEntityResolver implements EntityResolver { | ||
public static final EmptyStringEntityResolver INSTANCE = new EmptyStringEntityResolver(); | ||
|
||
@Override | ||
public InputSource resolveEntity(String publicId, String systemId) | ||
throws SAXException, IOException { | ||
return new InputSource(new StringReader("")); | ||
} | ||
} |
Oops, something went wrong.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, I have a question about the vulnerability, which is fixed via this commit. Is there a possibility, that also version 9.2.1002 (currently in rhel-7) is affected by this problem ? If it is so, is it possible to reproduce this problem in any way ? It may be problematic, as the code structure is quite different and many classes and properties are missing. Thanks for your advice.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that version has the same issue. The package structure is different but the XML handling code is similar. Compare these two methods in the 9.2.1002 class JdbcSQLXML with this PR:
getSource(...)
method:https://github.com/pgjdbc/pgjdbc/blob/REL9_2_1002/org/postgresql/jdbc4/Jdbc4SQLXML.java#L114-L151
getResult(...)
method:https://github.com/pgjdbc/pgjdbc/blob/REL9_2_1002/org/postgresql/jdbc4/Jdbc4SQLXML.java#L177-L214
Neither method sets any of the required security properties on the XML factories so they would be vulnerable to the same issue.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the description of the vulnerability: https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick replies! Currently we are working on a reproducer for this version. Hopefully, we will not need to backport tons of code, as it can cost us other security issues.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not make upgrades due to stability reasons, as rhel-7 is considered as a stable system, where we fix only high priority security issues. If we make an upgrade from version 9.* to 42.*, it can damage the functionality of other components.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with that, but for now, we see the problem is resolvable, so I consider to somehow backport the fix also to this version. We would highly appreciate your willingness to help us.
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please advice us, how it is possible to run the internal testsuite? We are aiming to reproduce the problem as a part of internal testsuite. Thanks
14b62ac
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the version you have it would be
ant test