blob: 0fe8a23e5e7e9f64b11199d8d75f62881566f353 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* <a href="https://commons.apache.org/xml">Apache Commons Secure XML</a> provides secure-by-default JAXP factory creation for Java. A single method call
* returns a secure JAXP factory that can be used to <em>safely</em> parse XML files.
* <p>
* Every method returns <em>new, secure</em> factory instances. No caching or pooling is performed; callers on a hot path are responsible for their own caching.
* </p>
* <p>
* A returned factory is not necessarily an instance of the underlying implementation. It might be (and usually is) a wrapper around it, so it cannot be cast to
* the implementation's own class. Everything else about the implementation's behavior is preserved: features, properties, and attributes delegate to it, and
* only the security behavior is secure.
* </p>
* <p>
* Preserved behavior includes the choice of internal parsers. Each TrAX, XPath, or schema implementation has its own way of instantiating them, and the library
* respects it:
* </p>
* <ul>
* <li>Stock JDK factories use the JDK parsers by default, and expose the {@code jdk.xml.overrideDefaultParser} feature (and Java system property of the same
* name) to switch to parsers instantiated through {@link java.util.ServiceLoader}.</li>
* <li>Saxon selects its parsers through its own configuration.</li>
* </ul>
* <p>
* Whichever parser is selected, it is secure.
* </p>
* <h2>Security Guarantees</h2>
* <p>
* Every factory returned by this library makes the same three guarantees, regardless of which JAXP implementation is on the classpath:
* </p>
* <ul>
* <li><strong>External DTDs are not fetched.</strong></li>
* <li><strong>External entities are not resolved.</strong></li>
* <li><strong>Internal entity expansion is bounded</strong> by the processing limits the parser applies, so DoS payloads such as Billion Laughs are rejected
* before they exhaust resources. The library enables {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} wherever the JAXP API mandates it, and the limits
* are then the implementation's secure defaults. The StAX API defines no such feature, and no Android parser supports it, so there the bound is whatever the
* implementation applies on its own, and this guarantee is <strong>best-effort</strong>.</li>
* </ul>
* <p>
* These guarantees are defined on OpenJDK 8 or later (and JDK distributions built from it). No version of Android supports
* {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING}, so on Android (API level 26 or later) the securing is applied as best-effort without a guarantee,
* tested as complete starting with API level 33; see the threat model's "Assumptions about the environment".
* </p>
* <p>
* The guarantees hold whether or not the caller opts into DTD validation ({@link javax.xml.parsers.DocumentBuilderFactory#setValidating(boolean)
* setValidating(true)}) or attaches a compiled XSD via {@link javax.xml.parsers.DocumentBuilderFactory#setSchema(javax.xml.validation.Schema) setSchema}: every
* external resource the validation would otherwise fetch (the DTD itself, an {@code xsi:schemaLocation} hint, an external entity referenced from the DTD)
* remains blocked.
* </p>
* <p>
* Each method adds factory-specific guarantees on top of the three above, documented on the corresponding {@code newXxxFactory()} method.
* </p>
* <p>
* Each factory class mirrors every static factory method of its JAXP counterpart:
* </p>
* <ul>
* <li>the class-name/class-loader overloads and the StAX {@code newFactory} family (JDK 8),</li>
* <li>{@code newDefaultInstance()} (Java 9), and</li>
* <li>the namespace-aware {@code newNSInstance()} family (Java 13).</li>
* </ul>
* <p>
* All of them work, with the same semantics, on every supported runtime, including Java 8.
* The {@code newDefaultInstance} methods are an <strong>opt-out of JAXP pluggability</strong>:
* they pin the platform's built-in implementation instead of whatever a classpath lookup would resolve,
* which suits a library with minimal XML requirements that does not want to delegate the choice of implementation to the application developer.
* The DOM, SAX and schema variants fall back to the standard lookup where the runtime provides neither the Java 9 method nor the JDK's built-in class
* (for example, Android, whose own lookup is pinned to the platform parser, and for schemas falls back to exactly the Xerces implementation).
* </p>
* <p>
* An unresolved external reference resolves to empty content by default, so the parse continues without the resource. To reject it with an exception instead,
* set the system property {@code org.apache.commons.xml.secure.throwOnUnresolved} to {@code true}; the property is read at resolution time, and references resolved by
* a caller-supplied resolver are unaffected.
* </p>
* <h2>Caller-supplied URIs</h2>
* <p>
* A top-level URI passed directly by the caller is fetched as-is: {@code StreamSource(systemId)}, {@code DocumentBuilder.parse(String)}, or a {@code SAXSource}
* built from a system id all cause the JAXP implementation to open that URI without consulting the secure layer. Use a {@link javax.xml.transform.URIResolver}
* or {@link org.xml.sax.EntityResolver} if you need to restrict the top-level fetch.
* </p>
* <h2>Thread safety</h2>
* <p>
* The returned factories inherit the thread-safety properties of the underlying JAXP implementation, which in practice means they are <strong>not guaranteed to
* be thread-safe</strong>. Create a new factory per thread or synchronize externally.
* </p>
*/
package org.apache.commons.xml.secure;