对于使用Java原生DOM和SAX以及DOM4J有以下两种修复方法(这里以DocumentBuilderFactory为例):

    1. //仅限
    2. Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
    3. documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);

    2.如果无法完全禁用DTD,可以采用以下操作一起使用

    1. // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities和http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
    2. // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities和http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
    3. // JDK7 + - http://xml.org/sax/features/external-general-entities和http://xml.org/sax/features/external-parameter-entities
    4. documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities",false);
    5. documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    1. documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);
    1. documentBuilderFactory.setXIncludeAware(false);
    2. documentBuilderFactory.setExpandEntityReferences(false);

    上述设置功能的方法setFeature也可以换成setAttribute,setAttribute方法用于用户在底层设置特定属性,使用方法和效果是一样的。
    上述防御需要Java 7 Update 67,Java 8 Update 20或更高版本,因为DocumentBuilderFactory和SAXParserFactory的上述对策在早期Java版本中被破坏。
    也可以从其他类上着手防范xxe漏洞:
    如XMLInputFactory、TransformerFactory、Validator、SchemaFactory、SAXTransformerFactory。但这些类都是调用了XMLConstants中的属性,故需要支持JAXP1.5.使用StAX解析xml文件时,可使用下面方法进行防范(这里仅用XMLInputFactory类做为例子:其他类的防护手段类似):

    //这将完全禁用该工厂的DTD
    xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD,false);
    //禁用外部实体
    xmlInputFactory.setProperty(“javax.xml.stream.isSupportingExternalEntities”,false);
    示例1还有一个解决方案是,定义一个CustomResolver类,这个类实现了org.xml.sax.EntityResolver接口。它可以让SAX应用定制对外部实体的处理。setEntityResolver()方法可以将对应的SAX驱动实例注册进来。这个定制的处理器使用的是一个为外部实体定义的简单的白名单。当输入不是任何指定的、安全地实体源路径时,resolverEntity()方法会返回一个空的InputSource对象。结果是,当解析恶意输入时,这个由自定义的解析器返回的空的InputStream对象会抛出java.net.MalformedURLException异常。需要注意的是,必须创建一个XMLReader对象,以便通过这个对象来设置自定义的实体解析器。

    1. class CustomResolver implements EntityResolver {
    2. public InputSource resolveEntity(String publicId, String systemId)
    3. throws SAXException, IOException {
    4. //check for known good entities
    5. String entityPath = "/home/username/java/xxe/file";
    6. if (systemId.equals(entityPath)) {
    7. System.out.println("Resolving entity: " + publicId + " " + systemId);
    8. return new InputSource(entityPath);
    9. } else {
    10. return new InputSource(); // Disallow unknown entities by returning a blank path
    11. }
    12. }
    13. }
    14. class XXE {
    15. private static void receiveXMLStream(InputStream inStream,DefaultHandler defaultHandler)
    16. throws ParserConfigurationException, SAXException, IOException {
    17. SAXParserFactory factory = SAXParserFactory.newInstance();
    18. SAXParser saxParser = null;
    19. try {
    20. saxParser = factory.newSAXParser();
    21. XMLReader reader = saxParser.getXMLReader();
    22. reader.setEntityResolver(new CustomResolver());
    23. reader.setErrorHandler(new DefaultHandler());
    24. InputSource is = new InputSource(inStream);
    25. reader.parse(is);
    26. ...
    27. } catch (ParserConfigurationException e) {
    28. ...
    29. } catch (SAXException e) {
    30. ...
    31. } catch (IOException e) {
    32. ...
    33. }
    34. }
    35. ...
    36. }