Injection Attacks-XML注入

注入攻擊

##XML注入php

雖然JSON的出現實現了服務器與客戶端之間的「輕量級」數據交流,可是,做爲另外一種流行的可行方案,許多web服務API同時仍是繼續支持XML。另外,除了web服務以外,XML也是許多使用XML schemas 實行數據交換的協議的基礎,例如RSS,Atom,SOAP,以及RDF等等,舉不勝舉。html

XML無處不在:它存在於web應用的服務器中,或者在瀏覽器中做爲XMLHttpRequest的請求和應答的格式,亦或在瀏覽器的擴展程序中。因爲應用普遍,XML成爲了吸引注入攻擊的目標。它受衆廣,同時經常使用的XML解析器,例如libxml2,容許對XML進行一些默認處理。libxml2常在DOM、SimpleXML和XMLReader擴展中的PHP中使用。當瀏覽器的XML交換很頻繁時,咱們要考慮到,XML做爲請求格式時,就算是認證用戶,也有可能正經過跨站腳本攻擊發送攻擊者所編寫的XML。前端

###XML外部實體注入攻擊web

面對XML外部實體攻擊(XXE)的脆弱點在於,XML解析器的庫每每都支持自定義的XML實體引用。你應該熟悉,XML擁有表示>、<和&apos 等特殊標記字符的實體,做爲對通常實體的標準補充。同時XML容許用戶在XML文檔內自定義實體,以此來擴展其標準實體集。這些自定義實體能夠直接寫在可選的DOCTYPE中,而它們表明的擴展值則可引用一個外部資源。正是普通XML的這種支持自定義引用、可引用外部資源內容的可擴展性,致使系統易受XXE的攻擊。一般,咱們的系統毫不應當容許不受信任的輸入以沒法預期的方式參與到系統交互中來,同時絕大大多數程序開發人員都不會考慮到XXE。所以值得咱們特別注意。瀏覽器

例如,讓咱們來試着定義一個新的自定義實體「harmless」。安全

<!DOCTYPE results [ <!ENTITY harmless "completely harmless"> ]>

如今,包含這個實體定義的XML文檔能夠在任何容許的地方引用&harmless;實體。服務器

<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless "completely harmless">]>
<results>
    <result>This result is &harmless;</result>
</results>

XML解析器,例如PHP DOM,在解析這段XML時,會在加載完文檔後當即處理這個自定義實體。所以,請求相關文本時,會獲得以下的返回:app

This result is completely harmless

無疑,好處是,自定義實體能夠用較短的實體名來表明重複的文本和XML。當XML須要遵照特定的語法規範,或者須要自定義實體使編輯更爲簡單時,這種方法並很多見。可是,考慮到遵照不信任外部輸入的原則,咱們要特別當心地對待應用程序中使用的全部XML,辨別它們的真正目的。下面的這個就確定不是無害的輸入:less

<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless SYSTEM
"file:///var/www/config.ini">]>
<results>
    <result>&harmless;</result>
</results>

取決於請求的本地文件的內容,某些內容可用於擴充&harmless;實體,這些內容能夠從XML解析器中提取出來,包含在web應用的輸出中,攻擊者看到它們,即會形成信息泄露。獲取的文件將會被解析成XML,除非避開某些能夠觸發解析的特殊字符,而這限制了泄露的範圍。若是文件被解析爲XML但並不包含有效的XML內容,系統會報錯,這樣一來能夠避免內容泄露。可是,PHP中有一個巧妙的「技倆」,能夠繞過這種範圍的限制,既使得攻擊者接收不到應答,遠程HTTP請求卻仍然能夠影響web應用。dom

PHP有三種經常使用的方法,用來解析和使用XML:PHP DOM、SimpleXML,以及XMLReader。這三種方法都須要使用libxml2擴展,也默認啓用外部實體支持。這種默認設置致使PHP在XXE面前很脆弱,而咱們在考慮web應用或XML應用庫的安全性時,很容易疏忽這一點。

你也知道,XHTML和HTML5均可以被序列化爲有效的XML,也就是說,某些XHTML頁面和被序列化的HTML5能夠被解析爲XML,例如,使用DOMDocument::loadXML(),而不是DOMDocument::loadHTML()時。這種XML解析方法在XEE注入的面前也很脆弱。注意,與XHTML DOCTYPES不一樣,libxml2目前甚至沒法識別HTML5 DOCTYPE,所以沒法讓其成爲有效的XML。

####XXE注入實例

#####文件內容和信息泄露

在早前的一個信息泄露的例子中,咱們注意到自定義實體可能引用一個外部文件。

<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless SYSTEM
"file:///var/www/config.ini">]>
<results>
    <result>&harmless;</result>
</results>

這會把文件內容擴展到自定義的&harmless;實體中。因爲全部相似的請求都是在本地完成的,這使得該應用有權限讀取的全部文件內容均可能被泄露。只要應用的輸出中包含了這個擴展了的實體,攻擊者就能夠查看那些文件,包括沒有公開的文件。因這種方式而形成內容泄露的文件是至關有限的,只能是XML文件,和不會形成XML解析錯誤的文件。可是,PHP能夠徹底忽略這種限制。

<?xml version="1.0"?>
<!DOCTYPE results [
    <!ENTITY harmless SYSTEM
    "php://filter/read=convert.base64-encode/resource=/var/www/config.ini"
    >
]>
<results>
    <result>&harmless;</result>
</results>

PHP容許經過URI訪問PHP wrapper,這是通常文件系統函數,如file_get_contents()、require()、require_once()、file()、和copy()等,接受的協議之一。PHP wrapper支持一些過濾器,這些過濾器運行在給定的資源上,結果能夠經過函數調用返回。在上述例子中,咱們對想要讀取的目標文件使用了convert.base-64-encode過濾器。

這意味着,攻擊者經過利用XXE的脆弱性,能夠用PHP讀取任何可讀的文件,不論文本格式如何。攻擊者只需用base64將應用輸出解碼,就能夠毫無顧忌的分析一大堆非公開文件的內容。儘管這自己不會直接傷害終端用戶或是應用後臺,可是它能讓攻擊者瞭解目標應用,從而以最小的代價、最低的風險發現應用的其餘弱點。

#####繞過訪問控制

訪問控制能夠經過各類方法來實現。因爲XXE攻擊是掛在web應用後臺的,它沒法使用當前用戶會話產生任何影響,可是攻擊者仍然能夠藉助從本地服務器發送請求,來繞事後臺訪問控制。咱們來看一下下面這個簡單的訪問控制:

if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !in_array(@$_SERVER['REMOTE_ADDR'], array(
        '127.0.0.1',
        '::1',
    ))
) {
    header('HTTP/1.0 403 Forbidden');
    exit(
        'You are not allowed to access this file.'
    );
}

這段PHP和無數的相似代碼都用於限制特定PHP文件對本地服務器的訪問,如 localhost。可是,應用前端的XXE脆弱性,正好爲攻擊者提供了繞過訪問控制所需的憑證,由於XML解析器發出的全部HTTP請求都來自localhost。

<?xml version="1.0"?>
<!DOCTYPE results [
    <!ENTITY harmless SYSTEM
    "php://filter/read=convert.base64-encode/resource=http://example.com/viewlog.php"
    >
]>
<results>
    <result>&harmless;</result>
</results>

若是隻有本地請求能夠查看日誌,攻擊者就能夠成功獲取日誌。一樣的思路也適用於只接受本地請求的維護和管理接口。

#####拒絕服務(DOS)

幾乎全部能夠控制服務器資源利用的東西,均可用於製造DOS攻擊。經過XML外部實體注入,攻擊者能夠發送任意的HTTP請求,從而在恰當的時候耗盡服務器資源。

下文中還有一些其餘的例子,經過XML實體擴展形成XXE攻擊,從而製造潛在的DOS攻擊。

####抵禦XML外部實體注入

這類攻擊十分「誘人「,但對它的防護也簡單的出奇。既然DOM、SimpleXML和XMLReader依賴於libxml2,咱們能夠簡單地利用libxml_disable_entity_loader()函數來禁止外部實體引用。與此同時,DOCTYPE中預約義的自定義實體卻不會受到影響,由於它們並無使用任何須要文件系統操做或發送HTTP請求的外部資源。

$oldValue = libxml_disable_entity_loader(true);
$dom = new DOMDocument();
$dom->loadXML($xml);
libxml_disable_entity_loader($oldValue);

在全部涉及經過字符串、文件或者遠程URI來加載XML時,都須要使用這些操做。

當應用程序及其大部分請求都不須要外部實體時,你能夠簡單地從全局禁掉外部資源加載。大多數時候,這比找出全部的XML加載實例來逐個操做要更好。記住,許多庫天生自帶XEE脆弱性:

libxml_disable_entity_loader(true);

每次須要臨時容許加載外部資源時,加載完後切記再把這裏設爲TRUE。例如,在將Docbook XML轉換爲HTML時,所使用的XSL樣式就是依賴於外部實體的,這裏須要外部實體,可是是無害的。

可是,libxml2函數毫不是"萬能鑰匙"。咱們須要確認,其餘用於解析或處理XML的擴展和PHP庫的引用外部實體的功能,都處於關掉狀態。

若是不能經過上述方法來開關外部實體引用,你還能夠檢查一下XML文檔是否聲明瞭DOCTYPE。若是聲明瞭,同時禁掉了外部實體,則能夠簡單地丟棄XML文檔,拒絕可能形成解析器脆弱性的不受信任的XML訪問,同時將這種行爲記錄爲一次可能的攻擊。咱們須要將這種行爲記錄下來,由於除此以外不會有任何系統報錯記錄。能夠在平常輸入驗證中進行這項檢查。可是,這種方法並不理想,筆者仍是強烈建議從源頭上解決外部實體的問題。

/**
 * Attempt a quickie detection
 */
$collapsedXML = preg_replace("/[:space:]/", '', $xml);
if(preg_match("/<!DOCTYPE/i", $collapsedXml)) {
    throw new \InvalidArgumentException(
        'Invalid XML: Detected use of illegal DOCTYPE'
    );
}

同時,值得注意的是,當咱們懷疑一段數據有多是某個攻擊的結果時,最好的方法是丟棄它,而不是繼續使用它。既然它已經表現出了危險,爲何還要繼續使用它呢?所以,將上述兩個步驟合併起來,咱們能夠在沒法丟棄數據時(例如第三方的庫),經過主動跳過壞數據起到保護做用。之因此咱們更願意徹底丟棄這些數據,還由於上文提到過的一個理由:libxml_disable_entity_loader()不會將自定義實體徹底禁掉,只有引用外部資源的纔會被禁掉。所以這仍有可能致使一個被稱爲XML實體擴展的注入攻擊。在下文中咱們會提到這種攻擊。

原文地址:Injection Attacks

本文系 OneAPM 工程師編譯整理。OneAPM 是應用性能管理領域的新興領軍企業,能幫助企業用戶和開發者輕鬆實現:緩慢的程序代碼和 SQL 語句的實時抓取。想閱讀更多技術文章,請訪問 OneAPM 官方博客

本文轉自 OneAPM 官方博客

相關文章
相關標籤/搜索