[
https://issues.apache.org/jira/browse/GROOVY-11979?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King updated GROOVY-11979:
-------------------------------
Description:
h3. Part 1: FactorySupport hardened factories (secure by default)
*What's included:*
* {{FactorySupport.java}}: every factory method now returns a hardened factory
by default
** {{createDocumentBuilderFactory()}} — delegates to
{{createDocumentBuilderFactory(false)}}; previously returned a bare JDK factory
** {{createSaxParserFactory()}} — delegates to
{{createSaxParserFactory(false)}}; previously returned a bare JDK factory
** {{createDocumentBuilderFactory(boolean allowDocTypeDeclaration)}} *(new)*
** {{createSaxParserFactory(boolean allowDocTypeDeclaration)}} *(new)*
** {{createXMLInputFactory()}} *(new)*
** {{createXMLInputFactory(boolean allowDocTypeDeclaration)}} *(new)*
** {{createTransformerFactory(boolean allowDocTypeDeclaration, boolean
allowExternalResources)}} *(new)*
** {{createSchemaFactory(String schemaLanguage)}} *(new)*
** {{createXPathFactory()}} *(new)*
* {{FactorySupport.java}}: added private quiet helpers for the new factory
types (SchemaFactory, XPathFactory, TransformerFactory {{setAttribute}},
XMLInputFactory {{setProperty}}).
* {{FactorySupportTest.java}}: 14 new tests covering hardening defaults on both
the zero-arg and boolean overloads, relax-flag round-trips for each factory
type.
*Hardening recipes applied:*
|| Factory || Settings ||
| DocumentBuilderFactory | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}}, {{XIncludeAware=false}},
{{ExpandEntityReferences=false}} |
| SAXParserFactory | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}} |
| XMLInputFactory | {{SUPPORT_DTD=allow}},
{{IS_SUPPORTING_EXTERNAL_ENTITIES=false}} |
| TransformerFactory | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}}, {{ACCESS_EXTERNAL_DTD}} and
{{ACCESS_EXTERNAL_STYLESHEET}} = {{"all"}} or {{""}} per
{{allowExternalResources}} |
| SchemaFactory | {{FEATURE_SECURE_PROCESSING=true}} (no {{ACCESS_EXTERNAL_*}}
— preserves legitimate {{<xs:import>}}) |
| XPathFactory | {{FEATURE_SECURE_PROCESSING=true}} |
*Compat notes:*
* Direct callers of the zero-arg {{createDocumentBuilderFactory()}} /
{{createSaxParserFactory()}} now receive hardened factories. Callers that
previously parsed DOCTYPE-bearing input through those factories must switch to
the {{(true)}} overload. Internal Groovy callers ({{XmlParser}},
{{XmlSlurper}}, {{XmlUtil}}, {{DOMBuilder}}) overlay their own settings on top
of the default and are unaffected.
* No public method signatures changed. No methods deprecated.
h3. Part 2: Route internal XML factory sites through FactorySupport; tighten
partial hardening
*Routing changes (refactor — no user-visible behaviour change):*
* {{XmlParser}}, {{XmlSlurper}}: replaced inline factory +
{{setFeatureQuietly}} hardening with
{{FactorySupport.createSaxParserFactory(allowDocTypeDeclaration)}}. Removed
unused {{XMLConstants}} / {{setFeatureQuietly}} imports.
* {{XmlUtil.newFactoryInstance}}: routed through
{{FactorySupport.createSaxParserFactory}}; method now declares {{throws
ParserConfigurationException}} (existing callers already declared it).
* {{XmlUtil}} schema validation paths (3 sites): routed through
{{FactorySupport.createSchemaFactory}}.
* {{DOMBuilder.parse}} static methods: routed through
{{FactorySupport.createDocumentBuilderFactory}}.
* {{StreamingDOMBuilder}}: replaced raw
{{DocumentBuilderFactory.newInstance()}} with
{{FactorySupport.createDocumentBuilderFactory()}}.
* {{DomToGroovy}}: routed through
{{FactorySupport.createDocumentBuilderFactory()}}; dropped redundant inline
{{setFeature}}.
* {{DOMCategory}} XPath (2 sites): routed through
{{FactorySupport.createXPathFactory()}}.
*New API:*
* {{DOMBuilder.newInstance(boolean validating, boolean namespaceAware, boolean
allowDocTypeDeclaration)}} — relax knob for the instance/DSL parsing path.
Existing zero-arg and 2-arg overloads default to hardened.
* {{SerializeOptions.allowExternalResources}} ({{boolean}}, default {{false}})
with getter/setter — relax knob for {{XmlUtil.serialize}} when transforming
XSLT that legitimately imports external resources.
*Tightening (one user-visible default change):*
|| Site || Was || Now ||
| {{XmlUtil.serialize}} TransformerFactory | only
{{disallow-doctype-decl=!allow}} | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}}, {{ACCESS_EXTERNAL_DTD}} and
{{ACCESS_EXTERNAL_STYLESHEET}} = {{""}} (or {{"all"}} per
{{allowExternalResources}}) |
| {{XmlUtil}} SchemaFactory (3 sites) | nothing |
{{FEATURE_SECURE_PROCESSING=true}} (no {{ACCESS_EXTERNAL_*}} — preserves
legitimate {{<xs:import>}}) |
| {{DOMCategory}} XPathFactory | nothing | {{FEATURE_SECURE_PROCESSING=true}} |
*Defence-in-depth (no observable user impact):*
* {{StreamingDOMBuilder}} factory hardening (factory used only for
{{newDocument()}}, not for parsing input).
* {{GrapeIvy}} Ivy descriptor parsing now hardened — inlined recipe (FSP +
{{disallow-doctype-decl}} + {{XIncludeAware=false}} +
{{ExpandEntityReferences=false}}) since {{groovy-grape-ivy}} does not depend on
{{groovy-xml}}.
* {{DomToGroovy}} now also has {{FEATURE_SECURE_PROCESSING=true}} (previously
only had {{disallow-doctype-decl}}).
*Tests:*
* New {{XmlSecurityTest.groovy}} with 14 cases pinning the secure-by-default
contract: XXE, billion-laughs and external-DTD blocked by default in
{{XmlParser}}/{{XmlSlurper}}/{{DOMBuilder.parse}};
{{allowDocTypeDeclaration=true}} relax knob still functional;
{{XmlUtil.serialize}} blocks external XSLT imports by default and respects
{{allowExternalResources=true}}; schema validation still resolves with FSP
enabled; {{DOMCategory}} XPath still evaluates.
*Verification:*
* {{:groovy-xml:test}} — 237 tests pass (223 existing + 14 new).
* Full {{:compileJava :compileGroovy}} — clean.
*Compat notes:*
* Single user-visible default flip: {{XmlUtil.serialize}} blocks external XSLT
imports unless {{SerializeOptions.allowExternalResources=true}}. Affects an
uncommon usage pattern (passing XSLT stylesheets through the serialize path);
documented in the new test cases and in the {{SerializeOptions}} javadoc.
* All other changes are internal refactor or defence-in-depth on paths that
don't parse external input.
was:
h3. Part 1 — FactorySupport hardened factories (secure by default)
*What's included:*
* {{FactorySupport.java}}: every factory method now returns a hardened factory
by default
** {{createDocumentBuilderFactory()}} — delegates to
{{createDocumentBuilderFactory(false)}}; previously returned a bare JDK factory
** {{createSaxParserFactory()}} — delegates to
{{createSaxParserFactory(false)}}; previously returned a bare JDK factory
** {{createDocumentBuilderFactory(boolean allowDocTypeDeclaration)}} *(new)*
** {{createSaxParserFactory(boolean allowDocTypeDeclaration)}} *(new)*
** {{createXMLInputFactory()}} *(new)*
** {{createXMLInputFactory(boolean allowDocTypeDeclaration)}} *(new)*
** {{createTransformerFactory(boolean allowDocTypeDeclaration, boolean
allowExternalResources)}} *(new)*
** {{createSchemaFactory(String schemaLanguage)}} *(new)*
** {{createXPathFactory()}} *(new)*
* {{FactorySupport.java}}: added private quiet helpers for the new factory
types (SchemaFactory, XPathFactory, TransformerFactory {{setAttribute}},
XMLInputFactory {{setProperty}}).
* {{FactorySupportTest.java}}: 14 new tests covering hardening defaults on both
the zero-arg and boolean overloads, relax-flag round-trips for each factory
type.
*Hardening recipes applied:*
|| Factory || Settings ||
| DocumentBuilderFactory | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}}, {{XIncludeAware=false}},
{{ExpandEntityReferences=false}} |
| SAXParserFactory | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}} |
| XMLInputFactory | {{SUPPORT_DTD=allow}},
{{IS_SUPPORTING_EXTERNAL_ENTITIES=false}} |
| TransformerFactory | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}}, {{ACCESS_EXTERNAL_DTD}} and
{{ACCESS_EXTERNAL_STYLESHEET}} = {{"all"}} or {{""}} per
{{allowExternalResources}} |
| SchemaFactory | {{FEATURE_SECURE_PROCESSING=true}} (no {{ACCESS_EXTERNAL_*}}
— preserves legitimate {{<xs:import>}}) |
| XPathFactory | {{FEATURE_SECURE_PROCESSING=true}} |
*Compat notes:*
* Direct callers of the zero-arg {{createDocumentBuilderFactory()}} /
{{createSaxParserFactory()}} now receive hardened factories. Callers that
previously parsed DOCTYPE-bearing input through those factories must switch to
the {{(true)}} overload. Internal Groovy callers ({{XmlParser}},
{{XmlSlurper}}, {{XmlUtil}}, {{DOMBuilder}}) overlay their own settings on top
of the default and are unaffected.
* No public method signatures changed. No methods deprecated.
h3. PR2 — Route internal XML factory sites through FactorySupport; tighten
partial hardening
*Routing changes (refactor — no user-visible behaviour change):*
* {{XmlParser}}, {{XmlSlurper}}: replaced inline factory +
{{setFeatureQuietly}} hardening with
{{FactorySupport.createSaxParserFactory(allowDocTypeDeclaration)}}. Removed
unused {{XMLConstants}} / {{setFeatureQuietly}} imports.
* {{XmlUtil.newFactoryInstance}}: routed through
{{FactorySupport.createSaxParserFactory}}; method now declares {{throws
ParserConfigurationException}} (existing callers already declared it).
* {{XmlUtil}} schema validation paths (3 sites): routed through
{{FactorySupport.createSchemaFactory}}.
* {{DOMBuilder.parse}} static methods: routed through
{{FactorySupport.createDocumentBuilderFactory}}.
* {{StreamingDOMBuilder}}: replaced raw
{{DocumentBuilderFactory.newInstance()}} with
{{FactorySupport.createDocumentBuilderFactory()}}.
* {{DomToGroovy}}: routed through
{{FactorySupport.createDocumentBuilderFactory()}}; dropped redundant inline
{{setFeature}}.
* {{DOMCategory}} XPath (2 sites): routed through
{{FactorySupport.createXPathFactory()}}.
*New API:*
* {{DOMBuilder.newInstance(boolean validating, boolean namespaceAware, boolean
allowDocTypeDeclaration)}} — relax knob for the instance/DSL parsing path.
Existing zero-arg and 2-arg overloads default to hardened.
* {{SerializeOptions.allowExternalResources}} ({{boolean}}, default {{false}})
with getter/setter — relax knob for {{XmlUtil.serialize}} when transforming
XSLT that legitimately imports external resources.
*Tightening (one user-visible default change):*
|| Site || Was || Now ||
| {{XmlUtil.serialize}} TransformerFactory | only
{{disallow-doctype-decl=!allow}} | {{FEATURE_SECURE_PROCESSING=true}},
{{disallow-doctype-decl=!allow}}, {{ACCESS_EXTERNAL_DTD}} and
{{ACCESS_EXTERNAL_STYLESHEET}} = {{""}} (or {{"all"}} per
{{allowExternalResources}}) |
| {{XmlUtil}} SchemaFactory (3 sites) | nothing |
{{FEATURE_SECURE_PROCESSING=true}} (no {{ACCESS_EXTERNAL_*}} — preserves
legitimate {{<xs:import>}}) |
| {{DOMCategory}} XPathFactory | nothing | {{FEATURE_SECURE_PROCESSING=true}} |
*Defence-in-depth (no observable user impact):*
* {{StreamingDOMBuilder}} factory hardening (factory used only for
{{newDocument()}}, not for parsing input).
* {{GrapeIvy}} Ivy descriptor parsing now hardened — inlined recipe (FSP +
{{disallow-doctype-decl}} + {{XIncludeAware=false}} +
{{ExpandEntityReferences=false}}) since {{groovy-grape-ivy}} does not depend on
{{groovy-xml}}.
* {{DomToGroovy}} now also has {{FEATURE_SECURE_PROCESSING=true}} (previously
only had {{disallow-doctype-decl}}).
*Tests:*
* New {{XmlSecurityTest.groovy}} with 14 cases pinning the secure-by-default
contract: XXE, billion-laughs and external-DTD blocked by default in
{{XmlParser}}/{{XmlSlurper}}/{{DOMBuilder.parse}};
{{allowDocTypeDeclaration=true}} relax knob still functional;
{{XmlUtil.serialize}} blocks external XSLT imports by default and respects
{{allowExternalResources=true}}; schema validation still resolves with FSP
enabled; {{DOMCategory}} XPath still evaluates.
*Verification:*
* {{:groovy-xml:test}} — 237 tests pass (223 existing + 14 new).
* Full {{:compileJava :compileGroovy}} — clean.
*Compat notes:*
* Single user-visible default flip: {{XmlUtil.serialize}} blocks external XSLT
imports unless {{SerializeOptions.allowExternalResources=true}}. Affects an
uncommon usage pattern (passing XSLT stylesheets through the serialize path);
documented in the new test cases and in the {{SerializeOptions}} javadoc.
* All other changes are internal refactor or defence-in-depth on paths that
don't parse external input.
> Consolidate XML factory hardening and document secure-by-default parsing
> ------------------------------------------------------------------------
>
> Key: GROOVY-11979
> URL: https://issues.apache.org/jira/browse/GROOVY-11979
> Project: Groovy
> Issue Type: Improvement
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
>
> h3. Part 1: FactorySupport hardened factories (secure by default)
> *What's included:*
> * {{FactorySupport.java}}: every factory method now returns a hardened
> factory by default
> ** {{createDocumentBuilderFactory()}} — delegates to
> {{createDocumentBuilderFactory(false)}}; previously returned a bare JDK
> factory
> ** {{createSaxParserFactory()}} — delegates to
> {{createSaxParserFactory(false)}}; previously returned a bare JDK factory
> ** {{createDocumentBuilderFactory(boolean allowDocTypeDeclaration)}} *(new)*
> ** {{createSaxParserFactory(boolean allowDocTypeDeclaration)}} *(new)*
> ** {{createXMLInputFactory()}} *(new)*
> ** {{createXMLInputFactory(boolean allowDocTypeDeclaration)}} *(new)*
> ** {{createTransformerFactory(boolean allowDocTypeDeclaration, boolean
> allowExternalResources)}} *(new)*
> ** {{createSchemaFactory(String schemaLanguage)}} *(new)*
> ** {{createXPathFactory()}} *(new)*
> * {{FactorySupport.java}}: added private quiet helpers for the new factory
> types (SchemaFactory, XPathFactory, TransformerFactory {{setAttribute}},
> XMLInputFactory {{setProperty}}).
> * {{FactorySupportTest.java}}: 14 new tests covering hardening defaults on
> both the zero-arg and boolean overloads, relax-flag round-trips for each
> factory type.
> *Hardening recipes applied:*
> || Factory || Settings ||
> | DocumentBuilderFactory | {{FEATURE_SECURE_PROCESSING=true}},
> {{disallow-doctype-decl=!allow}}, {{XIncludeAware=false}},
> {{ExpandEntityReferences=false}} |
> | SAXParserFactory | {{FEATURE_SECURE_PROCESSING=true}},
> {{disallow-doctype-decl=!allow}} |
> | XMLInputFactory | {{SUPPORT_DTD=allow}},
> {{IS_SUPPORTING_EXTERNAL_ENTITIES=false}} |
> | TransformerFactory | {{FEATURE_SECURE_PROCESSING=true}},
> {{disallow-doctype-decl=!allow}}, {{ACCESS_EXTERNAL_DTD}} and
> {{ACCESS_EXTERNAL_STYLESHEET}} = {{"all"}} or {{""}} per
> {{allowExternalResources}} |
> | SchemaFactory | {{FEATURE_SECURE_PROCESSING=true}} (no
> {{ACCESS_EXTERNAL_*}} — preserves legitimate {{<xs:import>}}) |
> | XPathFactory | {{FEATURE_SECURE_PROCESSING=true}} |
> *Compat notes:*
> * Direct callers of the zero-arg {{createDocumentBuilderFactory()}} /
> {{createSaxParserFactory()}} now receive hardened factories. Callers that
> previously parsed DOCTYPE-bearing input through those factories must switch
> to the {{(true)}} overload. Internal Groovy callers ({{XmlParser}},
> {{XmlSlurper}}, {{XmlUtil}}, {{DOMBuilder}}) overlay their own settings on
> top of the default and are unaffected.
> * No public method signatures changed. No methods deprecated.
> h3. Part 2: Route internal XML factory sites through FactorySupport; tighten
> partial hardening
> *Routing changes (refactor — no user-visible behaviour change):*
> * {{XmlParser}}, {{XmlSlurper}}: replaced inline factory +
> {{setFeatureQuietly}} hardening with
> {{FactorySupport.createSaxParserFactory(allowDocTypeDeclaration)}}. Removed
> unused {{XMLConstants}} / {{setFeatureQuietly}} imports.
> * {{XmlUtil.newFactoryInstance}}: routed through
> {{FactorySupport.createSaxParserFactory}}; method now declares {{throws
> ParserConfigurationException}} (existing callers already declared it).
> * {{XmlUtil}} schema validation paths (3 sites): routed through
> {{FactorySupport.createSchemaFactory}}.
> * {{DOMBuilder.parse}} static methods: routed through
> {{FactorySupport.createDocumentBuilderFactory}}.
> * {{StreamingDOMBuilder}}: replaced raw
> {{DocumentBuilderFactory.newInstance()}} with
> {{FactorySupport.createDocumentBuilderFactory()}}.
> * {{DomToGroovy}}: routed through
> {{FactorySupport.createDocumentBuilderFactory()}}; dropped redundant inline
> {{setFeature}}.
> * {{DOMCategory}} XPath (2 sites): routed through
> {{FactorySupport.createXPathFactory()}}.
> *New API:*
> * {{DOMBuilder.newInstance(boolean validating, boolean namespaceAware,
> boolean allowDocTypeDeclaration)}} — relax knob for the instance/DSL parsing
> path. Existing zero-arg and 2-arg overloads default to hardened.
> * {{SerializeOptions.allowExternalResources}} ({{boolean}}, default
> {{false}}) with getter/setter — relax knob for {{XmlUtil.serialize}} when
> transforming XSLT that legitimately imports external resources.
> *Tightening (one user-visible default change):*
> || Site || Was || Now ||
> | {{XmlUtil.serialize}} TransformerFactory | only
> {{disallow-doctype-decl=!allow}} | {{FEATURE_SECURE_PROCESSING=true}},
> {{disallow-doctype-decl=!allow}}, {{ACCESS_EXTERNAL_DTD}} and
> {{ACCESS_EXTERNAL_STYLESHEET}} = {{""}} (or {{"all"}} per
> {{allowExternalResources}}) |
> | {{XmlUtil}} SchemaFactory (3 sites) | nothing |
> {{FEATURE_SECURE_PROCESSING=true}} (no {{ACCESS_EXTERNAL_*}} — preserves
> legitimate {{<xs:import>}}) |
> | {{DOMCategory}} XPathFactory | nothing | {{FEATURE_SECURE_PROCESSING=true}}
> |
> *Defence-in-depth (no observable user impact):*
> * {{StreamingDOMBuilder}} factory hardening (factory used only for
> {{newDocument()}}, not for parsing input).
> * {{GrapeIvy}} Ivy descriptor parsing now hardened — inlined recipe (FSP +
> {{disallow-doctype-decl}} + {{XIncludeAware=false}} +
> {{ExpandEntityReferences=false}}) since {{groovy-grape-ivy}} does not depend
> on {{groovy-xml}}.
> * {{DomToGroovy}} now also has {{FEATURE_SECURE_PROCESSING=true}} (previously
> only had {{disallow-doctype-decl}}).
> *Tests:*
> * New {{XmlSecurityTest.groovy}} with 14 cases pinning the secure-by-default
> contract: XXE, billion-laughs and external-DTD blocked by default in
> {{XmlParser}}/{{XmlSlurper}}/{{DOMBuilder.parse}};
> {{allowDocTypeDeclaration=true}} relax knob still functional;
> {{XmlUtil.serialize}} blocks external XSLT imports by default and respects
> {{allowExternalResources=true}}; schema validation still resolves with FSP
> enabled; {{DOMCategory}} XPath still evaluates.
> *Verification:*
> * {{:groovy-xml:test}} — 237 tests pass (223 existing + 14 new).
> * Full {{:compileJava :compileGroovy}} — clean.
> *Compat notes:*
> * Single user-visible default flip: {{XmlUtil.serialize}} blocks external
> XSLT imports unless {{SerializeOptions.allowExternalResources=true}}. Affects
> an uncommon usage pattern (passing XSLT stylesheets through the serialize
> path); documented in the new test cases and in the {{SerializeOptions}}
> javadoc.
> * All other changes are internal refactor or defence-in-depth on paths that
> don't parse external input.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)