Search code examples
javaxmlsaxsaxparser

Disallow entity declarations but allow DTDs


I am given an XML document that must be allowed to have a Document Type Declaration (DTD), but we prohibit any ENTITY declarations.

The XML document is parsed with SAXParser.parse(), as follows:

SAXParserFactory factory = SAXParserFactory.newInstance();

factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setValidating(true);

SAXParser parser = factory.newSAXParser();

The XML is then passed into the parser as an InputSource:

InputSource inputSource= ... ;
parser.parse(inputSource, handler);

And the handler has a resolveEntity method, which SAXParser.parse() calls:

public InputSource resolveEntity(String pubID, String sysID) throws SAXException {
  InputSource inputSource = null;
  try {
     inputSource = entityResolver.resolveEntity(publicId, systemId);
  }
  catch (IOException e) {
     throw new SAXException(e);
  }
  return inputSource;
}

When I pass in an XML file with an ENTITY reference, it seems that nothing is being done - no exceptions are thrown and nothing is stripped - to or about the prohibited ENTITY reference.

Here is an example of the bad XML I am using. The DTD should be allowed, but the !ENTITY line should be disallowed:

<!DOCTYPE foo SYSTEM "foo.dtd" [
    <!ENTITY gotcha SYSTEM "file:///gotcha.txt"> <!-- This is disallowed-->
]>

<label>&gotcha;</label>

What do I need to do to make sure that ENTITY references are disallowed in the XML, but that DTDs are still allowed?


Solution

  • Set a org.xml.sax.ext.DeclHandler on the SaxParser.

    parser.setProperty("http://xml.org/sax/properties/declaration-handler", myDeclHandler);
    

    The DeclHandler gets notified when a internal entity declaration is parsed. To disallow entity decls you can simple throw a SAXException:

    public class MyDeclHandler extends org.xml.sax.ext.DefaultHandler2 {
         public void internalEntityDecl(String name, String value) throws SAXException {
             throw new SAXException("not allowed");
         }
    }