Properly configure SchemaFactory to prevent XEE attacks via the document being validated

Thomas Leplus <[email protected]> Tue, 13 Oct 2020 09:32:10 -0700
Newsgroups gmane.text.xml.xerces-j.user
Message-ID <CANHA9OFTa5sUEUFe7R6Q3ODZov+X8e0o4Y7cnoBH5sPbZSursw@mail.gmail.com>
--00000000000090b6be05b18ff5c4
Content-Type: text/plain; charset="UTF-8"

Hello,

I am trying to create a utility method to build a SchemaFactory configured
out-of-the-box to handle XML External Entity (XEE) attacks. The goal is to
have a centralized factory that takes care of all the configuration in a
single place.

I am currently doing this:

   SchemaFactory sf = SchemaFactory.newInstance(schemaLanguage);
   sf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
   sf.setFeature("http://apache.org/xml/features/disallow-doctype-decl",
true);

The idea is to disable all DTDs (which is OK in my case). But when I try
the following test:

    public static final String VALID_XML_SCHEMA
            = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
            + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">"
            + "  <xs:element name=\"note\"/>"
            + "</xs:schema>";

    public static final String VALID_XML_DOC_WITH_EXTERNAL_GENERAL_ENTITY
            = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
            + "<!DOCTYPE note ["
            + "  <!ELEMENT note ANY >"
            + "  <!ENTITY space SYSTEM \"note.dtd\">"
            + "]>"
            + "<note>&space;</note>";

   ...

   SchemaFactory factory =
SecureXML.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI);
   Schema schema = factory.newSchema(new StreamSource(new
ByteArrayInputStream(VALID_XML_SCHEMA.getBytes())));
   Validator validator = schema.newValidator();
   validator.validate(new StreamSource(new
ByteArrayInputStream(VALID_XML_DOC_WITH_EXTERNAL_GENERAL_ENTITY.getBytes())));

I get the following exception:

java.io.FileNotFoundException: note.dtd (No such file or directory)

Which means the DTD is not ignored and so the XEE vulnerability is still
there. Note that XXE attempts in the XSD itself seem to be thwarted.

I have tried the various approaches listed on the OWASP XEE cheatsheet (
https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html)
but as far as I can tell, none of them work with Xerces2.

Here is my complete pom.xml for reference:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.leplus.infsec</groupId>
  <artifactId>xee</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>xee</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>xalan</groupId>
      <artifactId>xalan</artifactId>
      <version>2.7.2</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>xerces</groupId>
      <artifactId>xercesImpl</artifactId>
      <version>2.12.0</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

I have also created a GitHub project (https://github.com/thomasleplus/xee)
with all my source code and JUnit test case if someone want to
reproduce/test the issue. I have also created a GitHub project (
https://github.com/thomasleplus/xee) with all my source code and JUnit test
case if someone wants to reproduce/test the issue.

Thank you in advance for any help you can provide,

Tom

--00000000000090b6be05b18ff5c4
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Hello,<br><br>I am trying to create a utility method to bu=
ild a SchemaFactory configured out-of-the-box to handle XML External Entity=
 (XEE) attacks. The goal is to have a centralized factory that takes care o=
f all the configuration in a single place.<br><br>I am currently doing this=
:<br><br><span style=3D"font-family:monospace">=C2=A0=C2=A0 SchemaFactory s=
f =3D SchemaFactory.newInstance(schemaLanguage);<br>=C2=A0=C2=A0 sf.setFeat=
ure(XMLConstants.FEATURE_SECURE_PROCESSING, true);<br>=C2=A0=C2=A0 sf.setFe=
ature(&quot;<a href=3D"http://apache.org/xml/features/disallow-doctype-decl=
" target=3D"_blank">http://apache.org/xml/features/disallow-doctype-decl</a=
>&quot;, true);</span><br><br>The idea is to disable all DTDs (which is OK =
in my case). But when I try the following test:<br><br><span style=3D"font-=
family:monospace">=C2=A0 =C2=A0 public static final String VALID_XML_SCHEMA=
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D &quot;&lt;?xml version=3D=
\&quot;1.0\&quot; encoding=3D\&quot;UTF-8\&quot;?&gt;&quot;<br>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + &quot;&lt;xs:schema xmlns:xs=3D\&quot;<a =
href=3D"http://www.w3.org/2001/XMLSchema%5C" target=3D"_blank">http://www.w=
3.org/2001/XMLSchema\</a>&quot;&gt;&quot;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 + &quot; =C2=A0&lt;xs:element name=3D\&quot;note\&quot;/&gt;&=
quot;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + &quot;&lt;/xs:schema&g=
t;&quot;;<br><br>=C2=A0 =C2=A0 public static final String VALID_XML_DOC_WIT=
H_EXTERNAL_GENERAL_ENTITY<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D =
&quot;&lt;?xml version=3D\&quot;1.0\&quot; encoding=3D\&quot;UTF-8\&quot;?&=
gt;&quot;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + &quot;&lt;!DOCTYPE=
 note [&quot;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + &quot; =C2=A0&=
lt;!ELEMENT note ANY &gt;&quot;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 + &quot; =C2=A0&lt;!ENTITY space SYSTEM \&quot;note.dtd\&quot;&gt;&quot=
;<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + &quot;]&gt;&quot;<br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 + &quot;&lt;note&gt;&amp;space;&lt;/=
note&gt;&quot;;<br><br>=C2=A0 =C2=A0...<br><br>=C2=A0 =C2=A0SchemaFactory f=
actory =3D SecureXML.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI=
);<br>=C2=A0 =C2=A0Schema schema =3D factory.newSchema(new StreamSource(new=
 ByteArrayInputStream(VALID_XML_SCHEMA.getBytes())));<br>=C2=A0 =C2=A0Valid=
ator validator =3D schema.newValidator();<br>=C2=A0 =C2=A0validator.validat=
e(new StreamSource(new ByteArrayInputStream(VALID_XML_DOC_WITH_EXTERNAL_GEN=
ERAL_ENTITY.getBytes())));<br></span><br>I get the following exception:<br>=
<span style=3D"font-family:monospace"><br>java.io.FileNotFoundException: no=
te.dtd (No such file or directory)</span><br><br>Which means the DTD is not=
 ignored and so the XEE vulnerability is still there. Note that XXE attempt=
s in the XSD itself seem to be thwarted.<br><br>I have tried the various ap=
proaches listed on the OWASP XEE cheatsheet (<a href=3D"https://cheatsheets=
eries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html=
" target=3D"_blank">https://cheatsheetseries.owasp.org/cheatsheets/XML_Exte=
rnal_Entity_Prevention_Cheat_Sheet.html</a>) but as far as I can tell, none=
 of them work with Xerces2.<br><br>Here is my complete pom.xml for referenc=
e:<br><span style=3D"font-family:monospace"><br>&lt;project xmlns=3D&quot;<=
a href=3D"http://maven.apache.org/POM/4.0.0" target=3D"_blank">http://maven=
.apache.org/POM/4.0.0</a>&quot;<br>xmlns:xsi=3D&quot;<a href=3D"http://www.=
w3.org/2001/XMLSchema-instance" target=3D"_blank">http://www.w3.org/2001/XM=
LSchema-instance</a>&quot;<br>=C2=A0 xsi:schemaLocation=3D&quot;<a href=3D"=
http://maven.apache.org/POM/4.0.0" target=3D"_blank">http://maven.apache.or=
g/POM/4.0.0</a><br><a href=3D"http://maven.apache.org/xsd/maven-4.0.0.xsd" =
target=3D"_blank">http://maven.apache.org/xsd/maven-4.0.0.xsd</a>&quot;&gt;=
<br>=C2=A0 &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br><br>=C2=A0 &lt=
;groupId&gt;org.leplus.infsec&lt;/groupId&gt;<br>=C2=A0 &lt;artifactId&gt;x=
ee&lt;/artifactId&gt;<br>=C2=A0 &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&g=
t;<br>=C2=A0 &lt;packaging&gt;jar&lt;/packaging&gt;<br><br>=C2=A0 &lt;name&=
gt;xee&lt;/name&gt;<br>=C2=A0 &lt;url&gt;<a href=3D"http://maven.apache.org=
" target=3D"_blank">http://maven.apache.org</a>&lt;/url&gt;<br><br>=C2=A0 &=
lt;properties&gt;<br>=C2=A0 =C2=A0 &lt;project.build.sourceEncoding&gt;UTF-=
8&lt;/project.build.sourceEncoding&gt;<br>=C2=A0 &lt;/properties&gt;<br><br=
>=C2=A0 &lt;dependencies&gt;<br>=C2=A0 =C2=A0 &lt;dependency&gt;<br>=C2=A0 =
=C2=A0 =C2=A0 &lt;groupId&gt;xalan&lt;/groupId&gt;<br>=C2=A0 =C2=A0 =C2=A0 =
&lt;artifactId&gt;xalan&lt;/artifactId&gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;vers=
ion&gt;2.7.2&lt;/version&gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;scope&gt;runtime&l=
t;/scope&gt;<br>=C2=A0 =C2=A0 &lt;/dependency&gt;<br>=C2=A0 =C2=A0 &lt;depe=
ndency&gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;groupId&gt;xerces&lt;/groupId&gt;<br=
>=C2=A0 =C2=A0 =C2=A0 &lt;artifactId&gt;xercesImpl&lt;/artifactId&gt;<br>=
=C2=A0 =C2=A0 =C2=A0 &lt;version&gt;2.12.0&lt;/version&gt;<br>=C2=A0 =C2=A0=
 =C2=A0 &lt;scope&gt;runtime&lt;/scope&gt;<br>=C2=A0 =C2=A0 &lt;/dependency=
&gt;<br>=C2=A0 =C2=A0 &lt;dependency&gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;groupI=
d&gt;junit&lt;/groupId&gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;artifactId&gt;junit&=
lt;/artifactId&gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;version&gt;4.12&lt;/version&=
gt;<br>=C2=A0 =C2=A0 =C2=A0 &lt;scope&gt;test&lt;/scope&gt;<br>=C2=A0 =C2=
=A0 &lt;/dependency&gt;<br>=C2=A0 &lt;/dependencies&gt;<br>&lt;/project&gt;=
</span><br><br>I have also created a GitHub project (<a href=3D"https://git=
hub.com/thomasleplus/xee" target=3D"_blank">https://github.com/thomasleplus=
/xee</a>) with all my source code and JUnit test case if someone want to re=
produce/test the issue. I have also created a GitHub project (<a href=3D"ht=
tps://github.com/thomasleplus/xee" target=3D"_blank">https://github.com/tho=
masleplus/xee</a>) with all my source code and JUnit test case if someone w=
ants to reproduce/test the issue.<br><br>Thank you in advance for any help =
you can provide,<br><br>Tom</div>

--00000000000090b6be05b18ff5c4--