Apache/Nginx中Host頭攻擊的一些差異
伺服器的域名(用於虛擬主機 ),以及伺服器所監聽的傳輸控制協議埠號。如果所請求的埠是對應的服務的標準埠,則埠號可被省略。
自超檔案傳輸協議版本1.1(HTTP/1.1)開始便是必需欄位。
以上是維基百科中對於Host頭部的說明。可以看到Host頭部並非是用於區別傳送到哪臺主機的欄位。而是用於區分一臺主機上不同的虛擬主機。(可以在Apache和Nginx中配置相應Host對應的虛擬主機。
利用PHP可以在 $_SERVER['HTTP_HOST']
欄位中獲取到該欄位的值
var_dump($_SERVER['HTTP_HOST']);
當沒有配置虛擬主機或者匹配不到對應的 Host
主機時,webserver就會發送請求到預設的目錄中去解析
從而 Host
頭部就變成了一個可控的欄位,當一些應用程式沒有對 $SERVER['HTTP_HOST']
欄位進行處理,過分信任時,就會產生一些安全問題
Diff of win/linux
這裡用的測試環境分別是
- win10下的 phpstudy
- ubuntu 18.04中預設安裝的nginx和apache2
在1.php中會輸出 $_SERVER['HTTP_HOST']
變數
Windows
Apache
可以任意修改apache中的值,伺服器都會預設接受
甚至可以插入兩個 Host
頭部,在win下會用 ,
將兩個頭部相連
Host: localhost Host:123468
Nginx
nginx中對於任意髒字符都是允許修改的
但是在插入兩個 Host
頭部的時候只會獲取到第二個 Host
值
Host: localhost Host: 'select user();
Linux
但是在linux中又會有些不同
Apache
linux下的apache就有著較為嚴格的限制,只允許修改對應的ip數字
插入一些髒字符就會返回400的錯誤
Host: 192.168.85.145'
兩個頭部也是一樣的情況,即使頭部是合法的
Host: 192.168.85.145 Host: 192.168.85.145
Nginx
linux下nginx中對於 Host
的處理類似於win中的就不過多介紹
從而網上有一些防禦手段就變成了設定虛擬主機(virtual host),從而可以確保 Host
欄位不會被更改,因為一旦修改了 Host
欄位就不會解析到對應的目錄當中。
Virtual Host
但即使配置了虛擬主機之後,所接受的 Host
欄位就是可以信任的麼?
在 Apache
、 Nginx
中會呈現不同的狀態
測試環境為
- ubuntu 18.04
- Apache/2.4.29 (Ubuntu)
- nginx/1.14.0 (Ubuntu)
- PHP 7.2.10-0ubuntu0.18.04.1
至於虛擬主機配置的部分就不過多介紹,在網上可以找到很多配置的文章
至於域名,可以買一個域名修改解析,或者直接修改host檔案
然後在 /var/www
目錄下新建了三個資料夾
html apache nginx
Apache
可以看到,在配置了虛擬主機之後,訪問對應的域名就會訪問到對應的目錄中
Host: localhost.ba123.top
當遇到一個不認識的域名的時候,就會解析到預設目錄下(當然,假如預設目錄下沒有 1.php
這個檔案就會返回一個404
Host: localhost.ba123.to
那想攻擊Apache中的虛擬主機時 Host
欄位就不能新增別的髒字符了麼?目前找到的可以新增的就只有通過冒號 :
分割開的埠號
只要是一個合法的埠就可以發起正常的請求
Host: localhost.ba123.top:23333
但是當想插入一些字元或者埠號過大的時候,都會拒絕請求,返回一個400,更不會允許兩個 Host
頭部的請求
Host: localhost.ba123.top:23333'select
總體來說,Apache對於 Host
欄位的限制還是比較嚴格的,在開啟了虛擬主機之後,幾乎比較難以插入髒字符。
Nginx
在nginx中似乎有著更多的攻擊手法
對於未知的主機名,處理方式還是與apache中一致,會解析到預設目錄中
Host: localhost.ba123.to'select
但是這裡假如利用冒號 :
的形式分割之後,冒號後面的 port
部分會直接被nginx給拋棄,從而可以插入任意的字元
Host: localhost.ba123.top'select sleep(5);
甚至在nginx中可以傳入兩個 Host
頭部,Nginx將以第一個為準傳送到對應的虛擬主機處理,而PHP-FPM將以第二個為準給 $_SERVER['HTTP_HOST']
賦值。
Host: localhost.ba123.top Host:'select sleep(5);
但是在apache中傳入兩個Host頭部的時候,就會直接返回400
由此可見,在ngin中對於 Host
的並沒有做過多的限制,從而可以比較容易的進行Host頭部攻擊。
windows上的虛擬主機原諒我確實沒怎麼遇到過,就沒測試了,感興趣的可以自己測試下。
Summary
可以看到 Host
頭部,在不同的情況下會呈現出不同的狀態,因此在編寫程式的時候一定要將 Host
這個值設定為不可信任的,對其進行一些正則或者轉義的一些過濾。否則極易引發安全問題。
在windows下對於這種頭部的限制比較鬆,apache和nginx都能比較輕鬆的繞過去。
而在兩個伺服器相比,Apache對於資料的解析更加嚴謹,尤其是在linux的環境中,極大的限制了非法的請求。
Nginx則甚至會出現 Nginx
與 PHP-FPM
解析不一致的情況,有時這種解析不一樣甚至會帶來更多的危害。