DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 避免 XPath 注入的危險
避免 XPath 注入的危險
編輯:XML詳解     

 隨著簡單 XML API、Web 服務和 Rich Internet Applications (RIAs) 的發展,更多組織幾乎在所有方面(從配置文件到遠程過程調用)都采用 XML 作為數據格式。一些人已經使用 XML 文檔代替更傳統的純文本文件或關系數據庫,但是與任何其他允許外部用戶提交數據的應用程序或技術相似,XML 應用程序可能容易受到代碼注入的攻擊,尤其是 XPath 注入攻擊。

  簡介

  隨著新技術的出現並得到很好的沿用,針對這些技術的威脅也隨之產生並逐漸增多。SQL 盲注攻擊是一種為人熟知的代碼注入攻擊形式,但是也有很多其他形式,有些尚未得到很好的記載和了解。最近開始出現的一種代碼注入攻擊是 XPath 注入攻擊,它利用了 XPath 解析器的松散輸入和容錯特性,讓心懷不滿的人能夠在 URL、表單或其他方法上附帶惡意的 XPath 查詢以獲得權限信息的訪問權並更改這些信息。

  本文考察了通常情況下如何執行 XPath 攻擊並提供了一個 Java™ 和 XML 環境中的例子。討論了如何檢測這類威脅,考察了如何減輕該威脅,最後討論了如何應對可疑的入侵。

  入門

  本文主要介紹代碼注入攻擊的一種特殊類型:XPath 盲注。如果您不熟悉 XPath 1.0 或需要了解基礎知識,請查看 W3 Schools XPath 教程(請參閱 參考資料 中的鏈接)。您還可以在 developerWorks 上找到大量的關於在各種語言環境中使用 XPath 的文章(請參閱 參考資料 中的鏈接)。本文使用的示例主要針對 XPath 1.0,但是也可用於 XPath 2.0。XPath 2.0 實際上增加了您可能遇到的問題。

  本文還提供了用於處理 Java JDK 5.0 的 Java 代碼示例。同時本文的概念和主題是跨平台的,如果您的應用程序使用 XPath 獲取特殊的代碼示例,那麼您必須使用 JDK 5.0。


 

代碼注入

  一種更常見的對 Web 應用程序的攻擊和威脅是某種形式的代碼注入,Wikipedia 將其定義為:

  ……利用系統沒有對其輸入進行強制執行或檢查的假設向計算機系統中引入(或 “注入”)代碼的技術。注入代碼的目的通常是繞過或修改程序的最初目標功能。如果被繞過的功能涉及系統安全,那麼結果可能是災難性的。

  快速浏覽任何相關 Web 站點(比如 Web Application Security Consortium 或 Security Focus,請參閱 參考資料 中的鏈接)都會顯示很多使用某種形式的代碼注入進行的攻擊,從 JavaScript 到 SQL 注入再到其他形式的代碼注入攻擊。最近開始出現的一種威脅(最初由 Amit Klein 於 2004 年在一篇論文中概述)是 XPath 盲注攻擊(請參閱 參考資料)。這種攻擊的運作跟 SQL 盲注攻擊幾乎完全相似,與 SQL 注入攻擊不同的是,幾乎沒什麼人了解 XPath 盲注攻擊或對其進行預防。與 SQL 注入攻擊類似,如果使用最佳實踐開發安全的應用程序,通常可以輕松地處理該威脅。

  XPath 攻擊

  一般說來,大多數 Web 應用程序使用關系數據庫存儲和檢索信息。例如,如果您的 Web 站點需要身份驗證,那麼您可能擁有一個 users 表,其中包含惟一 ID、登錄名、密碼,也許還有一些其他信息,比如角色。從 users 表中檢索用戶的 SQL 查詢可能類似於清單 1。

  清單 1. 從 users 表中檢索用戶的 SQL 查詢

Select * from users where loginID='foo' and passWord='bar'

  在這個查詢中,用戶必須提供 loginID 和 password 作為輸入。如果攻擊者在 loginID 字段中輸入:' or 1=1 並在 passWord 中輸入:' or 1=1,則形成的查詢將類似清單 2。

清單 2. 從攻擊者輸入形成的查詢

Select * from users where loginID = '' or 1=1 and passWord=' ' or 1=1

  這個條件會一直匹配,因此攻擊者可以進入系統。XPath 注入的原理大體類似。但是,假設您擁有的不是一個 users 表,而是一個 XML 文件,其中包含了如清單 3 所示的用戶信息。

  清單 3. user.XML

<?XML version="1.0" encoding="UTF-8"?>
<users>
   <user> 
     <firstname>Ben</firstname>
     <lastname>Elmore</lastname>
     <loginID>abc</loginID>
     <password>test123</passWord>
   </user>
   <user> 
     <firstname>Shlomy</firstname>
     <lastname>Gantz</lastname>
     <loginID>xyz</loginID>
     <password>123test</passWord>
   </user>
   <user> 
     <firstname>Jeghis</firstname>
     <lastname>Katz</lastname>
     <loginID>mrj</loginID>
     <password>jk2468</passWord>
   </user>
   <user> 
     <firstname>DarIEn</firstname>
     <lastname>Heap</lastname>
     <loginID>drano</loginID>
     <password>2mne8s</passWord>
   </user>
</users>

在 XPath 中,類似於 SQL 查詢的語句如清單 4 所示。

  清單 4. 匹配 SQL 查詢的 XPath 語句

//users/user[loginID/text()='abc' and passWord/text()='test123']

  要執行類似的攻擊以繞過身份驗證,您可能會使用類似清單 5 的方法。

  清單 5. 繞過身份驗證

//users/user[LoginID/text()='' or 1=1 and passWord/text()='' or 1=1]

  您可能在 Java 應用程序中有一個諸如 doLogin 之類的方法,使用 清單 3 中的 XML 文檔再次執行身份驗證。可能類似於清單 6。

  清單 6. XPathInjection.Java

import Java.io.IOException;
import org.w3c.dom.*;
import org.XML.sax.SAXException;
import Javax.XML.parsers.*;
import Javax.XML.xpath.*;
public class XpathInjectionExample {
 
    public boolean doLogin(String loginID, String passWord)
       throws ParserConfigurationException, SAXException,IOException,
XPathExpressionException {
     DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
     domFactory.setNamespaceAware(true);
     DocumentBuilder builder = domFactory.newDocumentBuilder();
     Document doc = builder.parse("users.XML");
     XPathFactory factory = XPathFactory.newInstance();
     XPath xpath = factory.newXPath();
     XPathExpression expr = xpath.compile("//users/user[loginID/text()='"+loginID+"'
and password/text()='"+passWord+"' ]/firstname/text()");
   Object result = expr.evaluate(doc, XPathConstants.NODESET);
     NodeList nodes = (NodeList) result;
//print first names to the console
     for (int i = 0; i < nodes.getLength(); i++) {
       System.out.println(nodes.item(i).getNodeValue());}
      
   
     if (nodes.getLength() >= 1) {       
       return true;}
       else
       {return false;}
    }
}


對於 清單 6,如果您傳入一個 login 和 password,比如 loginID = 'abc' 和 passWord = 'test123',則該類將返回 true(而且就本例而言,還會打印一列 first name 到控制台)。例如,如果您傳入類似 ' or 1=1 or ''=' 的值,那麼您也會得到 true 返回值,因為 XPath 會最終發現字符串變成了類似清單 7 的樣子。

  清單 7. 字符串

//users/user[loginID/text()='' or 1=1 or ''='' and passWord/text()='' or 1=1 or ''='']

  這個字符串會在邏輯上使查詢一直返回 true 並將一直允許攻擊者訪問系統。

  另一種可能性更大而且可能更加麻煩的 XPath 攻擊方式是,攻擊者可以利用 XPath 在應用程序中動態地操作 XML 文檔。

  提取 XML 文檔結構

  用於繞過身份驗證的查詢還可以用於提取 XML 文檔的信息。假設攻擊者猜測 XML 文檔中第一個子節點的名稱是 loginID 並且想要確認一下。攻擊者可以提供清單 8 所示的輸入。

  清單 8. 攻擊者提供的輸入

abc' or name(//users/LoginID[1]) = 'LoginID' or 'a'='b

  與 清單 7 中的 1=1 不同,清單 8 中給出的表達式檢查第一個子節點的名稱是否為 loginID。形成的查詢如清單 9 所示。

  清單 9. 查詢

String(//users[LoginID/text()='abc' or name(//users/LoginID[1]) =
'LoginID' or 'a=b' and passWord/text()=''])

  用試湊法,攻擊者可以檢查 XML 文檔的各個子節點並通過查看這個 XPath 表達式是否能促成成功的身份驗證以收集信息。攻擊者然後可能編寫出一個簡單的腳本,發送各種 XPath 注入並從系統中提取 XML 文檔,如 Klein 的論文中提及的那樣。

XPath 注入預防

  因為 XPath 注入攻擊與 SQL 注入攻擊非常類似,所以很多預防方法也類似。這些預防方法中,多數也可以類似地應用於預防其他類型的代碼注入攻擊。

  身份驗證

  不論面對何種應用程序、環境或語言,都應遵守以下的最佳實踐:

  假定所有輸入都可疑。

  不僅要驗證數據的類型,還要驗證其格式、長度、范圍和內容(例如,一個簡單的正則表達式 if (/^"*^';&<>()/) 就可以找出大多數可疑的特殊字符)。

  在客戶機和服務器上都要驗證數據,因為客戶機驗證非常容易繞過。

  根據安全軟件開發的最佳實踐,遵守一致的編寫和 [missing Word] 策略實現應用程序安全性(請參閱 參考資料 中 apache 的優秀 Web 服務列表)。

  在發布應用程序之前測試已知的威脅。參考資料 中的 “Fuzz Testing” 介紹了測試方法。

  參數化

  與多數數據庫應用程序不同,XPath 不支持參數化查詢的概念,但是您可以使用其他 API(比如 XQuery)模擬該概念。您不需要構建字符串表達式,然後傳給 XPath 解析器以便在運行時動態執行(如清單 10 所示),而是通過創建保存查詢的外部文件使查詢參數化(如 清單 11 所示)。

  清單 10. 傳給 XPath 解析器的字符串

"//users/user[LoginID/text()=' " + loginID+ " ' and passWord/text()='
"+ passWord +" ']"

  在清單 11 中,通過創建保存查詢的外部文件使查詢參數化。

  清單 11. dologin.xq

declare variable $loginID as xs:string external;
declare variable $passWord as xs:string external;//users/user[@loginID=
$loginID and @password=$passWord]


對 清單 11 稍加修改,也可以完成同樣的功能,如清單 12 所示。

  清單 12. XQuery 片段

Document doc = new Builder().build("users.XML");
XQuery xquery = new XQueryFactory().createXQuery(new File("
dologin.xq"));
Map vars = new HashMap();
vars.put("loginid", "abc");
vars.put("passWord", "test123");
Nodes results = xquery.execute(doc, null, vars).toNodes();
for (int i=0; i < results.size(); i++) {
  System.out.println(results.get(i).toXML());
}

  這樣可以防止重要的顯式變量 $loginID 和 $passWord 在運行時被作為可執行表達式處理。這樣就分開了執行邏輯與數據;遺憾的是,查詢參數化並不是 XPath 功能的一部分,但是可以從 SAXON 之類的開源解析器中免費獲取(請參閱 參考資料 中的鏈接)。某些其他解析器支持這種功能,而且它可以作為防止 XPath 注入的一種可靠方式。

  Web 服務器上的數據檢查

  要防止 XPath 注入和其他形式的代碼注入,應該檢查所有從 Web 服務器傳到後端服務的數據。例如,對於 apache 您可以使用 Mod_Security 篩選器(比如 SecFilterSelective THE_REQUEST "('|")")查找字符串中的單引號和雙引號並禁止它們。您也可以使用同樣的方法篩選和禁止其他形式的特殊字符,比如 ("*^';&><</),這些字符都可以用於各種注入攻擊。這種方法對於使用基於 REST 或 SOAP 的 XML 服務的應用程序可能很好,但是在其他情況下可能不適用。通常的最佳實踐是,從最初的設計到應用程序實現都采用智能安全設計。

  如果系統被破壞了怎麼辦?

  大多數組織都考慮到了威脅檢測和威脅拒絕,但很少為此作出規劃,對於一名合格的安全專家,如果系統遭到破壞怎麼辦。您應該總是假定最壞的場景並作出規劃。

  這在很大程度上取決於組織和遭遇入侵的系統類型,但通常的最佳方法是,讓系統脫機並等待專業的論證工程師檢查系統。有時人們直接讓系統脫機並重映像驅動器,但是這種做法消除了入侵的證據和入侵者可能給系統造成的其他損害的信息。如果可能的話,一直保留系統狀態以待安全專家檢查。

  結束語

  多數使用 XML 的應用程序不易受到 XPath 注入攻擊,不應該只是因為發現了一個特殊的漏洞就認為 XML 應用程序風險更大。同時,隨著越來越多的新平台的采用,比如 AJax 和 FLEX 或 Open Laszlo 之類的 RIA 平台,以及來自 Google 等組織的 XML 服務聯盟 —— 從與後端服務通信到持久性的幾乎所有應用嚴重依賴於使用 XML,開發人員需要意識到這些方法所帶來的威脅和風險。

  遺憾的是,解決問題的方法和原則總是落後於新的特殊威脅的出現。遵守良好的安全最佳實踐不僅能夠幫助您預防 XPath 注入攻擊,而且可以預防其他形式的攻擊。



 

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved