XML Attacks#

Extensible Markup Language (XML) 是 1990 年代隨著網際網路爆發而廣泛採用的資料格式,用於在組織之間交換機器可讀的資料。XML 可視為 HTML 的通用化版本——標籤和屬性名稱由文件作者自行定義,而非由規範固定。

雖然近年來 JSON 和 YAML 等格式逐漸取代 XML 的部分用途,但每個網頁伺服器仍然在某種程度上實作了 XML 解析。XML 漏洞通常發生在 validation(驗證)過程中,即使你的程式碼不直接處理 XML,你使用的第三方依賴很可能也會解析 XML。

XML 的用途#

  • XML 將資料項目包裹在標籤之間,標籤可以巢狀嵌套
  • 文件作者可選擇具有語意的標籤名稱,使文件具備自我描述性
  • XML 廣泛用於 API、設定檔、網頁伺服器組態等場景
<?xml version="1.0"?>
<catalog>
  <book id="7991728882998">
    <author>Sponden, Phillis</author>
    <title>The Evil Horse That Knew Karate</title>
    <genre>Young Adult Fiction</genre>
  </book>
</catalog>

驗證 XML(Validating XML)#

由於 XML 的標籤名稱是自由定義的,讀取資料的應用程式需要知道預期的文件結構。XML 文件的結構通常由正式的 grammar(文法)描述,用來驗證文件是否符合預期格式。

描述 XML 結構的兩種主要方式:

  • Document Type Definition (DTD):類似 Backus-Naur Form (BNF) 表示法,用於描述標籤、子標籤和資料類型
  • XML Schema Definition (XSD):更現代、更具表達力的替代方案

DTD 包含一些可能暴露 parser 的功能特性,是 XML 攻擊的主要來源。特別是支援 inline DTD(內嵌 DTD)的 parser 更容易受到攻擊,因為惡意使用者可以控制 DTD 的內容。

Document Type Definitions#

DTD 透過指定標籤、子標籤和預期的資料類型來描述 XML 文件的結構:

<!DOCTYPE catalog [
  <!ELEMENT catalog    (book+)>
  <!ELEMENT book       (author,title,genre,description)>
  <!ENTITY  author     (#PCDATA)>
  <!ENTITY  title      (#PCDATA)>
  <!ENTITY  genre      (#PCDATA)>
  <!ENTITY  description (#PCDATA)>
  <!ATTLIST book id CDATA>
]>

XML Bombs#

XML bomb 利用 inline DTD 來爆炸性地增加 XML parser 的記憶體使用量,耗盡伺服器所有可用記憶體,導致伺服器當機。

Internal Entity Declarations#

DTD 支援 internal entity declarations(內部實體宣告),這是一種在解析時展開的字串替換巨集。例如:

<?xml version="1.0"?>
<!DOCTYPE employees [
  <!ELEMENT employees (employee)*>
  <!ELEMENT employee (#PCDATA)>
  <!ENTITY company "Rock and Gravel Company">
]>
<employees>
  <employee>Fred Flintstone, &company;</employee>
  <employee>Barney Rubble, &company;</employee>
</employees>

解析時,&company; 會被替換為 Rock and Gravel Company

Billion Laughs 攻擊#

當內部實體宣告引用其他內部實體宣告時,問題就出現了。經典的 billion laughs 攻擊:

<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  ...
  <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

這個簡單的 XML 檔案在 DTD 完全展開時會佔用超過 3GB 的記憶體,包含超過十億次 lol 字串。攻擊者只需找到網站上接受 XML 上傳的 URL,就能輕鬆發動 denial-of-service 攻擊。

XML External Entity Attacks#

如果 XML parser 被設定為處理 inline DTD,攻擊者可以使用 external entity declarations(外部實體宣告)來探索本地檔案系統或觸發伺服器的網路請求。

外部實體的運作方式#

<?xml version="1.0" standalone="no"?>
<!DOCTYPE copyright [
  <!ELEMENT copyright (#PCDATA)>
  <!ENTITY copy PUBLIC "http://www.w3.org/xmlspec/copyright.xml">
]>
<copyright>&copy;</copyright>

外部實體宣告中的 URL 可以使用不同的網路協定前綴:

  • http:// — 觸發 HTTP 請求
  • file:// — 讀取本地磁碟上的檔案

駭客如何利用外部實體#

  • 攻擊者製作惡意 XML 檔案,引用 file:///etc/passwd 等敏感檔案
  • 當 parser 將外部檔案插入 XML 文件後,文件格式可能變得不合法,導致解析失敗
  • Parser 會在錯誤訊息中包含被引用檔案的內容,攻擊者藉此讀取敏感資料

外部實體也可被用於發動 Server-Side Request Forgery (SSRF) 攻擊。天真設定的 XML parser 遇到帶有網路協定前綴的外部實體 URL 時,就會發出網路請求。駭客利用這個特性來探測內部網路、對第三方發動 denial-of-service 攻擊,或偽裝惡意 URL 呼叫。

保護你的 XML Parser(Securing Your XML Parser)#

最簡單的修復方式是:停用 inline DTD 的處理。DTD 是過時的技術,inline DTD 更是不良實踐。事實上,許多現代 XML parser 預設已經停用了這些功能。

各語言的安全設定#

Python#

使用 defusedxml 函式庫,它是 Python 標準 XML 解析函式庫的安全替代品,會明確拒絕 inline DTD。

Ruby#

使用 Nokogiri 函式庫,從 1.5.4 版本起已針對 XML 攻擊進行強化。

Node.js#

Node.js 有多種 XML 解析模組(xml2jsparse-xmlnode-xml),大多數預設不處理 DTD,但仍應查閱你使用的 parser 的文件確認。

Java#

透過 javax.xml.parsers.DocumentBuilderFactory 設定安全解析:

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

.NET#

XmlDictionaryReaderXmlNodeReaderXmlReader 預設是安全的。對於其他 parser(如 System.Xml.XmlDocument),設定 ProhibitDtd 屬性:

XmlTextReader reader = new XmlTextReader(stream);
reader.ProhibitDtd = true;

其他考量#

  • 遵循 principle of least privilege(最小權限原則):XML parser 幾乎沒有理由需要發出對外網路請求,考慮鎖定伺服器的對外網路存取
  • 如需對外網路存取(例如呼叫第三方 API),應在防火牆規則中設定白名單
  • 限制網頁伺服器可存取的磁碟目錄:Linux 上使用 chroot jail,Windows 上手動設定可存取的目錄白名單

總結#

  • XML 是廣泛使用的資料格式,你的 XML parser 若設定為接受並處理 inline DTD,就可能受到攻擊
  • XML bombs 利用 inline DTD 爆炸性地增加記憶體使用,可能導致伺服器當機
  • XML external entity attacks 利用外部實體引用本地檔案或網路位址,竊取敏感資訊或發動惡意網路請求
  • 確保使用經過安全強化的 XML parser,並停用 inline DTD 解析