使用 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 输入本身(<calcinput>...</calcinput>
部分)使用 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 攻击的主要内容,如果未能解决你的问题,请参考以下文章