【问题标题】:How to prevent XXE attack如何防止 XXE 攻击
【发布时间】:2017-03-31 15:44:43
【问题描述】:

我们对代码进行了安全审计,其中提到我们的代码容易受到 XML 外部实体 (XXE) 攻击。

说明

XML 外部实体攻击受益于在处理时动态构建文档的 XML 特性。一个 XML entity 允许动态地包含来自给定资源的数据。外部实体允许 XML 文档包含数据 来自外部 URI。除非另外配置,否则外部实体会强制 XML 解析器访问指定的资源 通过 URI,例如,本地计算机或远程系统上的文件。此行为将应用程序暴露给 XML External 实体 (XXE) 攻击,可用于执行本地系统的拒绝服务,获得对文件的未经授权的访问 本地机器,扫描远程机器,并对远程系统执行拒绝服务。

以下 XML 文档显示了 XXE 攻击的示例。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>

如果 XML 解析器尝试将实体替换为 /dev/random 文件。

推荐

应该安全地配置 XML 解组器,以使其不允许外部实体作为传入 XML 的一部分 文件。

为避免 XXE 注入,请勿使用将 XML 源直接处理为 java.io.Filejava.io.Readerjava.io.InputStream。使用安全配置的解析器解析文档,并使用将安全解析器作为 XML 源的解组方法,如下例所示:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(<XML Source>);
Model model = (Model) u.unmarshal(document);

以下代码是审计发现 XXE 攻击的地方:

Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
System.out.println("outputing to : " + outputLocation);
File outputFile = new File(outputLocation);
StreamResult result = new StreamResult(outputFile);
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);

如何在我的代码中实施上述建议?我在哪里漏掉了东西?

【问题讨论】:

标签: java xml xml-parsing transform


【解决方案1】:

由于市场上有大量的xml解析引擎,所以防止XXE攻击的方式因引擎而异。请参阅您的引擎文档。这里的基础是防止外部 DOCTYPE 声明。如果需要外部 DOCTYPE 声明,则禁用外部常规实体和外部参数实体将防止 XXE 攻击您的代码。下面是使用 SAX 解析器时防止 XXE 的示例代码。

public class MyDocumentBuilderFactory {

 public static DocumentBuilderFactory newDocumentBuilderFactory() {

    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

    try {
        documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
        
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities",false);
        
        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities",false)


    } catch(ParserConfigurationException exp){
        exp.printStackTrace();
    }

    return documentBuilderFactory;
 }
}

【讨论】:

    【解决方案2】:

    请注意,单独使用 FEATURE_SECURE_PROCESSING 似乎不够安全(来自blackhat-pdf):

    ...尽管 Oracle 推荐 XML 解析器实际上并不限制外部连接 特征 _SECURE_PROCESSING 已启用。

    OWASP 推荐 ACCESS_EXTERNAL_DTD 和 ACCESS_EXTERNAL_STYLESHEET。

    这将使得:

    TransformerFactory trfactory = TransformerFactory.newInstance();
    trfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    trfactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
    trfactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
    

    其实这个问题是重复的:How to Prevent XML External Entity Injection on TransformerFactory

    【讨论】:

      【解决方案3】:

      您可以使用与DocumentBuilderFactory 相同的方法:

      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
      ...
      

      要让每个人都自动使用它,您需要创建自己的实现(通过扩展您当前使用的实现;使用您的调试器来找出答案)。在构造函数中设置特征。

      然后你可以将System属性javax.xml.parsers.DocumentBuilderFactory中使用的新工厂传递给Java VM,每个人都会使用它。

      【讨论】:

        【解决方案4】:

        您需要在TransformerFactory 上开启安全处理功能。它将限制某些可能的恶意事件的发生(DOS 攻击等)

        TransformerFactory tf = TransformerFactory.newInstance();
        tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        Transformer transformer = tf.newTransformer();
        

        【讨论】:

        • 感谢您的回复,是的,但我需要在现有逻辑中实现 DocumentBuilderFactory....顺便说一句,我使用了您给定的建议,但收到错误“方法 setFeature(String, boolean) 未定义该类型变压器”。
        • 呃,不好意思,需要在TransformerFactory中设置。
        • 谢谢卡亚曼!它工作正常,但你能帮助用 DocumentBuilderFactory 概念替换 TransformerFactory 概念吗?真的会很明显。
        • 谁能帮忙?感谢任何人的帮助!
        猜你喜欢
        • 2012-10-10
        • 1970-01-01
        • 2012-12-23
        • 2015-10-10
        • 1970-01-01
        • 1970-01-01
        • 2018-01-19
        • 2016-05-01
        • 1970-01-01
        相关资源
        最近更新 更多