使用 JAXB 防止 XXE 攻击

Posted

技术标签:

【中文标题】使用 JAXB 防止 XXE 攻击【英文标题】:Prevent XXE Attack with JAXB 【发布时间】:2012-10-10 05:57:13 【问题描述】:

最近,我们对代码进行了安全审计,其中一个问题是我们的应用程序受到了Xml eXternal Entity (XXE) 攻击。

基本上,该应用程序是一个计算器,通过 Web 服务接收 XML 格式的输入。

以下是对我们的应用程序进行此类 XXE 攻击的示例:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <foo:calculateStuff>
         <!--Optional:-->
         <xmlInput><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE currency [  
   <!ENTITY include SYSTEM "file:///d:/" >]>
<calcinput>...</calcinput>
]]></xmlInput>
      </foo:calculateStuff>
   </soapenv:Body>
</soapenv:Envelope>

如您所见,我们可以引用指向外部文件 ("file:///d:/") 的实体。

关于 XML 输入本身(&lt;calcinput&gt;...&lt;/calcinput&gt; 部分)使用 JAXB (v2.1) 解组。 Web 服务部分基于 jaxws-rt (2.1)。

我需要做些什么来保护我的网络服务?

【问题讨论】:

【参考方案1】:

JAXB

您可以通过从 XMLStreamReader 中解组来防止 Xml 外部实体 (XXE) 攻击,该 XMLStreamReader 属性设置为 IS_SUPPORTING_EXTERNAL_ENTITIES 和/或 XMLInputFactory.SUPPORT_DTD 属性设置为 false

JAX-WS

JAX-WS 实现应该为您解决这个问题。如果不是,我建议针对特定实现打开一个错误。


示例

演示

package xxe;

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo 

    public static void main(String[] args) throws Exception 
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        XMLInputFactory xif = XMLInputFactory.newFactory();
        xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
        xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
        XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource("src/xxe/input.xml"));

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Customer customer = (Customer) unmarshaller.unmarshal(xsr);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    


input.xml

此 XML 文档包含一个实体,该实体已设置为获取我用于创建此示例的文件列表。

<?xml version="1.0"?>
<!DOCTYPE customer
[
<!ENTITY name SYSTEM "/Users/bdoughan/Examples/src/xxe/">
]
>
<customer>
  <name>&name;</name>
</customer>

客户

package xxe;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer 

    private String name;

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    


输出 - 默认配置

默认情况下实体将被解析。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <name>Customer.java
Demo.java
input.xml
</name>
</customer>

XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES 属性设置为 false 时的输出

设置此属性后,实体不会被解析。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <name></name>
</customer>

XMLInputFactory.SUPPORT_DTD 属性设置为 false 时的输出

当设置此属性时,尝试解析实体时会引发异常。

Exception in thread "main" javax.xml.bind.UnmarshalException
 - with linked exception:
[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15]
Message: The entity "name" was referenced, but not declared.]
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:436)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:372)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:342)
    at xxe.Demo.main(Demo.java:18)
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[8,15]
Message: The entity "name" was referenced, but not declared.
    at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next(XMLStreamReaderImpl.java:598)
    at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:196)
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:370)
    ... 2 more

【讨论】:

感谢您非常详细的回答!我还有一个小问题:当我设置xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); 时,我得到以下ParseError实体“include”被引用,但未声明。但是,如果我删除此属性(但保留第一个属性),则 XML 被正确解析。有什么想法吗? @BlaiseDoughan 有没有办法启用实体,但将它们限制为 5 或 10 的值?我们收到在用户输入的某些字段中带有“&”的请求。 @asgs - 您可以指定 VM 级别的实体扩展限制。见:blog.bdoughan.com/2011/03/… @BlaiseDoughan,创建一个安全配置的 XMLInputFactory 然后为每个实例文档创建一个新的 XMLStreamReader 是否安全/线程安全? 我有一个 Spring MVC Web 服务,我在其中配置了如上所述的编组和解组,但我仍然在 Acunetix 工具中获得 XML 外部实体注入。请帮助!

以上是关于使用 JAXB 防止 XXE 攻击的主要内容,如果未能解决你的问题,请参考以下文章

利用XML外部实体注入XXE攻击漏洞

XML (XXE) 注入Payload List

如何有效防止API的重放攻击(转自阿里云)

如何防止网站不被SQL注入攻击

使用 AFNetworking 防止中间人攻击

防止重放攻击最有效的方法是