HPP是HTTP Parameter Pollution的縮寫。這個漏洞由S. di Paola 與L. Caret Toni在2009年的OWASP上首次公佈。這也是一種注入型的漏洞,攻擊者通過在HTTP請求中插入特定的參數來發起攻擊。如果Web應用中存在這樣的漏洞,可以被攻擊者利用來進行客戶端或者服務器端的攻擊。下面對這個漏洞的原理做一下詳細解釋。
首先講下HTTP的參數處理
在跟服務器進行交互的過程中,客戶端往往會在GET/POST請求裏面帶上參數:
GET /foo?<span style="color:#ff0000;">par1=val1&par2=val2</span> HTTP/1.1
User-Agent: Mozilla/5.0
Host: Host
Accept: */*
POST /foo HTTP/1.1
User-Agent: Mozilla/5.0
Host: Host
Accept: */*
Content-Length: 19
如上面的例子所示,這些參數會以名稱-值對的形勢出現,通常在一個請求中,同樣名稱的參數只會出現一次。但是在HTTP協議中是允許同樣名稱的參數出現多次的。大家可以在下面給出的W3School鏈接上試試看:
http://www.w3schools.com/html/tryit.asp?filename=tryhtml_form_checkbox
但是針對同樣名稱的參數出現多次的情況,不同的服務器的處理方式會不一樣,比如看下面的2個例子:
http://www.google.com/search?q=italy&q=china
http://search.yahoo.com/search?p=italy&p=china
如果同時提供2個搜索的關鍵字參數給Google,那麼Google會對2個參數都進行查詢;但是Yahoo則不一樣,它只會處理後面一個參數。下面這個表簡單列舉了一些常見的Web服務器對同樣名稱的參數出現多次的處理方式:
Web服務器 |
參數獲取函數 |
獲取到的參數 |
PHP/Apache |
$_GET(“par”) |
Last |
JSP/Tomcat |
Request.getParameter(“par”) |
First |
Perl(CGI)/Apache |
Param(“par”) |
First |
Python/Apache |
getvalue(“par”) |
All (List) |
ASP/IIS |
Request.QueryString(“par”) |
All (comma-delimited string) |
那麼這會有什麼問題嗎?實際上這本身並沒有什麼問題,但是前提是Web應用程序的開發者知道這個事情並且有正確的進行處理。否則的話那麼難免會對攻擊者造成可乘之機。如果對同樣名稱的參數出現多次的情況沒有進行正確處理的話,那麼可能會導致漏洞使得攻擊者能夠利用來發起對服務器端或客戶端的攻擊。下面舉一些例子來詳細說明。
對客戶端的攻擊
比如有這樣一個網站,用來給其他人在2個候選人之間投票,這個網站的URL和代碼是這樣的:
Url : http://host/election.jsp?poll_id=4568
Link1: <a href="vote.jsp?poll_id=4568&candidate=zhang">爲張三投票</a>
Link2: <a href="vote.jsp?poll_id=4568&candidate=li">爲李四投票</a>
因爲種種原因,這個頁面裏面用於投票的鏈接實現的方式如下:
ID = Request.getParameter("pool_id")
href_link = "vote.jsp?poll_id=" + ID + "&candidate=xyz"
如果這時候惡意攻擊者生成了如下的一個URL發給投票人:
http_://host/election.jsp?poll_id=4568%26candidate%3Dzhang
那麼最終在頁面的內容會是:
Url : http://host/election.jsp?poll_id=4568%26candidate%3Dzhang
Link1: <a href="vote.jsp?poll_id=4568&candidate=zhang&candidate=zhang">爲張三投票</a>
Link2: <a href="vote.jsp?poll_id=4568&candidate=zhang&candidate=li">爲李四投票</a>
前面我們有知道對於JSP來說在有2個相同的名稱的參數的時候,會取第一個值:
Web服務器 |
參數獲取函數 |
獲取到的參數 |
JSP/Tomcat |
Request.getParameter(“par”) |
First |
所以不管投票人選擇的是誰,始終都是張三得票。
一般來說,對客戶端的攻擊一般會是如下流程,導致用戶選擇不期望的選項:
對服務器端的攻擊
比如某網站的實現如下:
void private executeBackendRequest(HTTPRequest request){
String action=request.getParameter("action");
String user=request.getParameter("userid");
String target=request.getParameter("target");
HttpRequest("http://centralauthencationserver/checkpriviledge.jsp", "POST","action="+action+"&user="+user+"&target="+target);}
/* get feedback of whether this user has privilege to perform specified action. If no such privilege, return error, otherwise continue perform the action*/
HttpRequest("http://businessserver/performaction.php", "POST","action="+action+"&user="+user+"&target="+target);}
它有個獨立的集中認證服務器用來做用戶權限方面的認證,另外的業務服務器專門用來處理業務,對外的門戶實際上緊緊只是用來做請求的轉發。這裏不會有SQL注入之類的漏洞,因爲不管是集中認證服務器還是業務處理服務器都會對傳入的參數的格式做檢查,確保不會存在SQL注入。那麼哪兒有問題?因爲集中認證服務器和業務處理服務器分別由2個團隊開發,使用了不同的腳本語言,又沒有考慮到HPP的情況。那麼看看一個本來緊緊只是具有隻讀權限的用戶,如果發送如下請求給服務器:
http_://frontHost/page?action=view&userid=zhangsan&target=bizreport%26action%3dedit
那麼根據我們知道的Web服務器參數處理的方式,這個用戶可以通過認證做一些本來沒有權限做的事情。
Web服務器 |
參數獲取函數 |
獲取到的參數 |
PHP/Apache |
$_GET(“par”) |
Last |
JSP/Tomcat |
Request.getParameter(“par”) |
First |
除此以外,HPP還可以被攻擊者用來繞過一些Web應用防火牆(WAF, WebApp Firewall),比如對某頁面的SQL注入攻擊如下:
show_user.aspx?id=5;select+1,2,3+from+users+where+id=1--
這個攻擊因爲在參數id裏面存在明顯的SQL注入的模板:select…from…而會被WAF成功攔截。但是如果換成HPP的方式:
show_user.aspx?id=5;select+1&id=2&id=3+from+users+where+id=1--
這時候沒有任何參數具備select…from…的特徵,可能就可以繞過WAF的攔截了。
總的來說,HPP是一種新的注入型漏洞。要防止這種漏洞,除了要做好對輸入參數的格式驗證外,另外還需要意識到HTTP協議是允許同名的參數的,在整個應用的處理過程中要意識到這一點從而根據業務的特徵對這樣的情況作正確的處理。
轉自:http://blog.csdn.net/eatmilkboy/article/details/6761407