Java代碼審計實戰:XML外部實體注入(XXE)深度解析
XML外部實體注入(XXE)是Web應用程序中一種常見但又常常被忽視的漏洞。它利用了XML解析器解析XML文檔時,允許引用外部實體這個特性。如果解析器沒有禁用外部實體引用,攻擊者就可以通過構造惡意XML,從而導致敏感信息泄露、服務器端請求偽造(SSRF)、甚至命令執行。
1. 漏洞的本質:不可信的XML被信任
XML外部實體注入的根源在于XML解析器。XML文檔支持使用實體(Entity)來定義可重用的數據。實體分為內部實體和外部實體。內部實體在文檔內部定義,而外部實體則可以引用外部資源,例如本地文件或遠程URL。當XML解析器沒有正確配置,允許處理外部實體時,就產生了XXE漏洞。
一個典型的XXE攻擊XML文檔:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<user><name>&xxe;</name>
</user>
這段XML代碼聲明了一個名為xxe
的外部實體,它的值是服務器上的/etc/passwd
文件。當不安全的XML解析器解析這個文檔時,它會去讀取/etc/passwd
文件的內容,并將其替換到&xxe;
的位置,從而導致敏感文件內容泄露。
2. Java代碼中的XXE常見表現形式
在Java中,許多處理XML的庫在默認配置下都容易受到XXE攻擊。常見的漏洞點通常出現在以下場景:
案例一:使用不安全的DOM或SAX解析器
在傳統的Java開發中,使用 javax.xml.parsers
包來解析XML非常普遍。然而,如果開發者沒有禁用對外部實體的支持,就會存在XXE漏洞。
// 不安全的DOM解析器代碼
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File("user.xml"));
//...
漏洞分析:
DocumentBuilderFactory.newInstance()創建的實例,在默認情況下通常會啟用外部實體處理。攻擊者可以向服務器上傳或提交一個包含惡意實體的XML文件,當服務器使用這段代碼解析時,就會觸發XXE。
案例二:使用不安全的XML相關庫
除了標準的 javax.xml.parsers
包,許多其他的XML相關庫或框架也可能存在類似問題。例如,當Spring框架在處理XML請求時,如果配置不當,也可能導致XXE。
不安全的代碼示例:
@PostMapping(path = "/api/user", consumes = "application/xml")
public String createUser(@RequestBody String xmlData) {// 假設內部使用不安全的XML解析庫SAXParserFactory spf = SAXParserFactory.newInstance();SAXParser saxParser = spf.newSAXParser();XMLReader xmlReader = saxParser.getXMLReader();// ...
}
漏洞分析:
這段代碼接收XML格式的請求體,如果內部的XML解析器沒有正確配置,攻擊者可以提交一個包含外部實體的XML,從而發起XXE攻擊。
案例三:利用XXE進行SSRF攻擊
XXE漏洞不僅可以用于讀取本地文件,還可以用于發起服務器端請求偽造(SSRF)。攻擊者可以通過外部實體引用來請求內部網絡資源,例如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://192.168.1.100:8080/admin/user?id=1">
]>
<data>&xxe;</data>
漏洞分析:
當服務器解析這段XML時,它會向內網地址192.168.1.100:8080發起請求。如果內網服務沒有訪問控制,攻擊者就可以利用這種方式探測內網服務、獲取內部數據,甚至執行其他惡意操作。
3. 歷史案例:Wordpress XML-RPC XXE 漏洞
在早期的Wordpress版本中,其XML-RPC接口存在XXE漏洞。攻擊者可以發送一個惡意的XML-RPC請求,利用XXE來讀取服務器上的任意文件,例如wp-config.php
,從而獲取數據庫連接信息。這個漏洞的嚴重性在于,它允許攻擊者在不進行身份驗證的情況下,竊取到系統的敏感配置信息,為后續的攻擊(如數據庫滲透)提供了便利。
4. 審計與加固:構建XXE的防御體系
防御XXE漏洞的核心在于禁用外部實體引用。
審計重點:
尋找XML處理入口:在代碼庫中搜索所有與XML解析相關的API和庫,如
DocumentBuilderFactory
、SAXParserFactory
、XMLReader
,以及Spring MVC中@RequestBody
注解接收application/xml
的地方。追蹤數據流:檢查所有XML數據來源,看它們是否來自不可信的用戶輸入。
安全修復方案:
為了徹底杜絕XXE,必須在所有XML解析器中禁用對外部實體和DTD的支持。以下是針對不同解析器的防御方法:
DocumentBuilderFactory
:DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 禁用 DTD dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); // 禁用外部通用實體 dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); // 禁用外部參數實體 dbf.setXIncludeAware(false); // 禁用 XInclude
SAXParserFactory
:SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); spf.setFeature("http://xml.org/sax/features/external-general-entities", false); spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
XMLInputFactory
(StAX解析器):XMLInputFactory xif = XMLInputFactory.newFactory(); xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
Spring Framework:
在Spring MVC中,可以使用MappingJackson2XmlHttpMessageConverter或Jaxb2Marshaller來處理XML,并確保它們的底層解析器都進行了安全配置。