隨著(zhù)新技術(shù)的出現并得到很好的沿用,針對這些技術(shù)的威脅也隨之產(chǎn)生并逐漸增多。SQL 盲注攻擊是一種為人熟知的代碼注入攻擊形式,但是也有很多其他形式,有些尚未得到很好的記載和了解。最近開(kāi)始出現的一種代碼注入攻擊是 XPath 注入攻擊,它利用了 XPath 解析器的松散輸入和容錯特性,讓心懷不滿(mǎn)的人能夠在 URL、表單或其他方法上附帶惡意的 XPath 查詢(xún)以獲得權限信息的訪(fǎng)問(wèn)權并更改這些信息。
本文考察了通常情況下如何執行 XPath 攻擊并提供了一個(gè) Java™ 和 XML 環(huán)境中的例子。討論了如何檢測這類(lèi)威脅,考察了如何減輕該威脅,最后討論了如何應對可疑的入侵。
本文主要介紹代碼注入攻擊的一種特殊類(lèi)型:XPath 盲注。如果您不熟悉 XPath 1.0 或需要了解基礎知識,請查看 W3 Schools XPath 教程(請參閱 參考資料 中的鏈接)。您還可以在 developerWorks 上找到大量的關(guān)于在各種語(yǔ)言環(huán)境中使用 XPath 的文章(請參閱 參考資料 中的鏈接)。本文使用的示例主要針對 XPath 1.0,但是也可用于 XPath 2.0。XPath 2.0 實(shí)際上增加了您可能遇到的問(wèn)題。
本文還提供了用于處理 Java JDK 5.0 的 Java 代碼示例。同時(shí)本文的概念和主題是跨平臺的,如果您的應用程序使用 XPath 獲取特殊的代碼示例,那么您必須使用 JDK 5.0。
一種更常見(jiàn)的對 Web 應用程序的攻擊和威脅是某種形式的代碼注入,Wikipedia 將其定義為:
……利用系統沒(méi)有對其輸入進(jìn)行強制執行或檢查的假設向計算機系統中引入(或 “注入”)代碼的技術(shù)。注入代碼的目的通常是繞過(guò)或修改程序的最初目標功能。如果被繞過(guò)的功能涉及系統安全,那么結果可能是災難性的。
快速瀏覽任何相關(guān) Web 站點(diǎn)(比如 Web Application Security Consortium 或 Security Focus,請參閱 參考資料 中的鏈接)都會(huì )顯示很多使用某種形式的代碼注入進(jìn)行的攻擊,從 JavaScript 到 SQL 注入再到其他形式的代碼注入攻擊。最近開(kāi)始出現的一種威脅(最初由 Amit Klein 于 2004 年在一篇論文中概述)是 XPath 盲注攻擊(請參閱 參考資料)。這種攻擊的運作跟 SQL 盲注攻擊幾乎完全相似,與 SQL 注入攻擊不同的是,幾乎沒(méi)什么人了解 XPath 盲注攻擊或對其進(jìn)行預防。與 SQL 注入攻擊類(lèi)似,如果使用最佳實(shí)踐開(kāi)發(fā)安全的應用程序,通??梢暂p松地處理該威脅。
一般說(shuō)來(lái),大多數 Web 應用程序使用關(guān)系數據庫存儲和檢索信息。例如,如果您的 Web 站點(diǎn)需要身份驗證,那么您可能擁有一個(gè) users 表,其中包含惟一 ID、登錄名、密碼,也許還有一些其他信息,比如角色。從 users 表中檢索用戶(hù)的 SQL 查詢(xún)可能類(lèi)似于清單 1。
Select * from users where loginID='foo' and password='bar' |
在這個(gè)查詢(xún)中,用戶(hù)必須提供 loginID 和 password 作為輸入。如果攻擊者在 loginID 字段中輸入:' or 1=1 并在 password 中輸入:' or 1=1,則形成的查詢(xún)將類(lèi)似清單 2。
Select * from users where loginID = '' or 1=1 and password=' ' or 1=1 |
這個(gè)條件會(huì )一直匹配,因此攻擊者可以進(jìn)入系統。XPath 注入的原理大體類(lèi)似。但是,假設您擁有的不是一個(gè) users 表,而是一個(gè) XML 文件,其中包含了如清單 3 所示的用戶(hù)信息。
<?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 中,類(lèi)似于 SQL 查詢(xún)的語(yǔ)句如清單 4 所示。
//users/user[loginID/text()='abc' and password/text()='test123'] |
要執行類(lèi)似的攻擊以繞過(guò)身份驗證,您可能會(huì )使用類(lèi)似清單 5 的方法。
//users/user[LoginID/text()='' or 1=1 and password/text()='' or 1=1] |
您可能在 Java 應用程序中有一個(gè)諸如 doLogin 之類(lèi)的方法,使用 清單 3 中的 XML 文檔再次執行身份驗證??赡茴?lèi)似于清單 6。
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("http://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,如果您傳入一個(gè) login 和 password,比如 loginID = 'abc' 和 password = 'test123',則該類(lèi)將返回 true(而且就本例而言,還會(huì )打印一列 first name 到控制臺)。例如,如果您傳入類(lèi)似 ' or 1=1 or ''=' 的值,那么您也會(huì )得到 true 返回值,因為 XPath 會(huì )最終發(fā)現字符串變成了類(lèi)似清單 7 的樣子。
//users/user[loginID/text()='' or 1=1 or ''='' and password/text()='' or 1=1 or ''=''] |
這個(gè)字符串會(huì )在邏輯上使查詢(xún)一直返回 true 并將一直允許攻擊者訪(fǎng)問(wèn)系統。
另一種可能性更大而且可能更加麻煩的 XPath 攻擊方式是,攻擊者可以利用 XPath 在應用程序中動(dòng)態(tài)地操作 XML 文檔。
用于繞過(guò)身份驗證的查詢(xún)還可以用于提取 XML 文檔的信息。假設攻擊者猜測 XML 文檔中第一個(gè)子節點(diǎn)的名稱(chēng)是 loginID 并且想要確認一下。攻擊者可以提供清單 8 所示的輸入。
abc' or name(//users/LoginID[1]) = 'LoginID' or 'a'='b |
與 清單 7 中的 1=1 不同,清單 8 中給出的表達式檢查第一個(gè)子節點(diǎn)的名稱(chēng)是否為 loginID。形成的查詢(xún)如清單 9 所示。
String(//users[LoginID/text()='abc' or name(//users/LoginID[1]) = 'LoginID' or 'a=b' and password/text()='']) |
用試湊法,攻擊者可以檢查 XML 文檔的各個(gè)子節點(diǎn)并通過(guò)查看這個(gè) XPath 表達式是否能促成成功的身份驗證以收集信息。攻擊者然后可能編寫(xiě)出一個(gè)簡(jiǎn)單的腳本,發(fā)送各種 XPath 注入并從系統中提取 XML 文檔,如 Klein 的論文中提及的那樣。
因為 XPath 注入攻擊與 SQL 注入攻擊非常類(lèi)似,所以很多預防方法也類(lèi)似。這些預防方法中,多數也可以類(lèi)似地應用于預防其他類(lèi)型的代碼注入攻擊。
不論面對何種應用程序、環(huán)境或語(yǔ)言,都應遵守以下的最佳實(shí)踐:
if (/^"*^';&<>()/) 就可以找出大多數可疑的特殊字符)。 與多數數據庫應用程序不同,XPath 不支持參數化查詢(xún)的概念,但是您可以使用其他 API(比如 XQuery)模擬該概念。您不需要構建字符串表達式,然后傳給 XPath 解析器以便在運行時(shí)動(dòng)態(tài)執行(如清單 10 所示),而是通過(guò)創(chuàng )建保存查詢(xún)的外部文件使查詢(xún)參數化(如 清單 11 所示)。
"http://users/user[LoginID/text()=' " + loginID+ " ' and password/text()=' "+ password +" ']" |
在清單 11 中,通過(guò)創(chuàng )建保存查詢(xún)的外部文件使查詢(xún)參數化。
declare variable $loginID as xs:string external; declare variable $password as xs:string external;//users/user[@loginID= $loginID and @password=$password] |
對 清單 11 稍加修改,也可以完成同樣的功能,如清單 12 所示。
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 在運行時(shí)被作為可執行表達式處理。這樣就分開(kāi)了執行邏輯與數據;遺憾的是,查詢(xún)參數化并不是 XPath 功能的一部分,但是可以從 SAXON 之類(lèi)的開(kāi)源解析器中免費獲?。ㄕ垍㈤?參考資料 中的鏈接)。某些其他解析器支持這種功能,而且它可以作為防止 XPath 注入的一種可靠方式。
要防止 XPath 注入和其他形式的代碼注入,應該檢查所有從 Web 服務(wù)器傳到后端服務(wù)的數據。例如,對于 Apache 您可以使用 Mod_Security 篩選器(比如 SecFilterSelective THE_REQUEST "(\'|\")")查找字符串中的單引號和雙引號并禁止它們。您也可以使用同樣的方法篩選和禁止其他形式的特殊字符,比如 ("*^';&><</),這些字符都可以用于各種注入攻擊。這種方法對于使用基于 REST 或 SOAP 的 XML 服務(wù)的應用程序可能很好,但是在其他情況下可能不適用。通常的最佳實(shí)踐是,從最初的設計到應用程序實(shí)現都采用智能安全設計。
大多數組織都考慮到了威脅檢測和威脅拒絕,但很少為此作出規劃,對于一名合格的安全專(zhuān)家,如果系統遭到破壞怎么辦。您應該總是假定最壞的場(chǎng)景并作出規劃。
這在很大程度上取決于組織和遭遇入侵的系統類(lèi)型,但通常的最佳方法是,讓系統脫機并等待專(zhuān)業(yè)的論證工程師檢查系統。有時(shí)人們直接讓系統脫機并重映像驅動(dòng)器,但是這種做法消除了入侵的證據和入侵者可能給系統造成的其他損害的信息。如果可能的話(huà),一直保留系統狀態(tài)以待安全專(zhuān)家檢查。
多數使用 XML 的應用程序不易受到 XPath 注入攻擊,不應該只是因為發(fā)現了一個(gè)特殊的漏洞就認為 XML 應用程序風(fēng)險更大。同時(shí),隨著(zhù)越來(lái)越多的新平臺的采用,比如 Ajax 和 FLEX 或 Open Laszlo 之類(lèi)的 RIA 平臺,以及來(lái)自 Google 等組織的 XML 服務(wù)聯(lián)盟 —— 從與后端服務(wù)通信到持久性的幾乎所有應用嚴重依賴(lài)于使用 XML,開(kāi)發(fā)人員需要意識到這些方法所帶來(lái)的威脅和風(fēng)險。
遺憾的是,解決問(wèn)題的方法和原則總是落后于新的特殊威脅的出現。遵守良好的安全最佳實(shí)踐不僅能夠幫助您預防 XPath 注入攻擊,而且可以預防其他形式的攻擊。
聯(lián)系客服