一次性付費進群,長期免費索取教程,沒有付費教程。
進微信群回復公眾號:微信群;QQ群:460500587
教程列表 見微信公眾號底部菜單 | 本文底部有推薦書籍微信公眾號:計算機與網絡安全
ID:Computer-network
在Web系統中,允許用戶上傳文件作為一個基本功能是必不可少的,如論壇允許用戶上傳附件,多媒體網站允許用戶上傳圖片,視頻網站允許上傳頭像、視頻等。但如果不能正確地認識到上傳帶來的風險,不加防範,會給整個系統帶來毀滅性的災難。
在PHP項目中,提供上傳功能並在伺服器端未對上傳的文件格式進行合理的校驗是存在巨大風險的。如果惡意攻擊者利用上傳漏洞上傳一些webshell,則可能完全控制整個網站程序,執行系統命令,獲取資料庫連結字串進行操作資料庫等危險操作。
1、文件上傳漏洞
以下是一個不安全的上傳代碼示例,即文件上傳PHP接收代碼upload.php。
<?php
$upload_dir='uploads'; // 用戶上傳文件保存目錄
$upload_file=$upload_dir.basename($_FILES['userfile']['name']);
if(move_uploaded_file($_FILES['userfile']['tmp_name'],$uploadfile)) {
echo "恭喜您,文件上傳成功";
} else {
echo "文件上傳失敗";
}
?>
以下是文件上傳HTML代碼upload.html。
<form name="upload" action="upload.php" method="POST" ENCTYPE="multipart/form-data">
請選擇上傳文件:
<input type"file" name="userfile">
<input type"submit" name="upload" value="上傳">
</form>
這是一個簡單的上傳文件功能,其中由用戶上傳文件,如果上傳成功,保存文件的路徑為http://伺服器路徑/uploads/文件名稱。
如果攻擊者上傳一個如下內容的hacker.php腳本文件到伺服器:
<?php
system($_GET['shell']);
?>
則攻擊者就可以通過該文件進行URL請求http://伺服器路徑/uploads/hacker.php?shell=ls%20-al,從而可以執行任何shell命令。
圖1所示是惡意腳本的執行結果,其中列出了該目錄下的所有文件。
圖1 上傳漏洞造成的webshell執行結果
2、檢查文件類型防止上傳漏洞
上面例子中的代碼非常簡單,並沒有進行任何的上傳限制。如果要限制,通常的做法是限制文件上傳類型。
下面在PHP代碼中增加了文件類型限制來防止上傳漏洞。
<?php
if($_FILES['userfile']['type']!="image/gif") {
die("請上傳正確的文件類型");
}
$uploaddir='uploads';
$uploadfile=$uploaddir.basename($_FILES['userfile']['name']);
if(move_uploaded_file($_FILES['userfile']['tmp_name'],$uploadfile)) {
echo "恭喜您,文件上傳成功";
} else {
echo "文件上傳失敗";
}
?>
在這種情況下,如果攻擊者試圖上傳shell.php,則應用程式在上傳請求中將檢查文件MIME類型。以下是拒絕上傳的HTTP請求返回數據包。
POST /upload.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE,close
Host: localhost:8080
User-Agent: Mozilla/5.0(Macintosh: Inter Mac OS X10_13_2)
AppleWebKit/537.36(KHTML,like gecko) Chrome/65.0.3325.181
Safari/537.36
Content-Type: multipart/form-data;boundary=xYzzY
Content-Length:32
--s76f8a7sf8as9f8a9f80as8df--
Content-Disposition: form-data;name="userfile";filename="shell.php"
Content-Type: text/plain
<?php
system($_GET['shell']);
?>
--s76f8a7sf8as9f8a9f80as8df--
HTTP/1.1 200 OK
Date: Thu, 31 May 2019 22:00:01 GMT
Server: Apache
X-Powered-By: PHP/5.6
Content-Length: 30
Connection: close
Content-Type: text/html
請上傳正確的文件類型
這裡成功地通過檢測類型防止了非授權類型文件的上傳,伺服器拒絕接收文件。
但是如果只進行上傳文件類型的檢查也是不夠的,攻擊者通過修改POST數據包中Content-Type:text/plain欄位為Content-Type:image/gif,然後發送數據包,即可成功實現惡意腳本的上傳。
3、檢查文件擴展名稱防止上傳漏洞
除了檢查文件類型外,研發人員最常用的防範方法之一,就是基於白名單或者黑名單,驗證所傳文件的擴展名稱是否符合。以下代碼通過黑名單方式對文件類型進行限制。
<?php
$blacklist=array(".php","phtml",".php3",".php4"); // 黑名單
$uploaddir='uploads/';
$uploadfile=$uploaddir.basename($_FILES['userfile']['name']);
$item==substr($_FILES['userfile']['name'],-4);
if(in_array($item,$whitelist)) {
die("請上傳正確的文件類型");
}
if(move_uploaded_file($_FILES['userfile']['tmp_name'],$uploadfile)) {
echo "恭喜您,文件上傳成功";
} else {
echo "上傳失敗";
}
?>
以下是白名單模式限制文件類型的代碼示例。
<?php
$whitelist=array(".jpg",".gif","png"); //白名單
$uploaddir='uploads/';
$uploadfile=$uploaddir.basename($_FILES['userfile']['name']);
$item==substr($_FILES['userfile']['name'],-4);
if(!in_array($item,$whitelist)) {
die("請上傳正確的文件類型");
}
if(move_uploaded_file($_FILES['userfile']['tmp_name'],$uploadfile)) {
echo "恭喜您,文件上傳成功";
} else {
echo "上傳文件失敗";
}
?>
從黑名單和白名單兩種不同的驗證方法來看,白名單方式絕對要比黑名單安全得多。但是,並不是說採用白名單方式驗證就足夠安全了。
IIS服務存在一個漏洞(Microsoft Internet Infomation Server 6.0 ISAPI Filename Analytic Vulnerability),如上傳一個名為hacker.php;.gif的文件到伺服器,PHP腳本文件因限制最後4個字符,所以本文件是合法的,但是當上傳後瀏覽該文件——http://伺服器路徑/uploads/hacker.php;.gif時,就可以繞過Web程序的邏輯檢查,從而能導致伺服器以IIS進程權限執行任意惡意用戶定義的腳本。此漏洞只針對於IIS特定版本。
在Apache程序中,同樣存在一個由擴展名解析的漏洞。當惡意攻擊上傳一個有多個擴展名的PHP腳本文件時,如果最後的擴展名未定義,就會解析前一個擴展,比如hacker.php.2018文件。當將該文件上傳時,如果是以白名單、黑名單方式進行驗證,就可以繞過驗證,上傳非法文件到伺服器,當瀏覽http://伺服器路徑/uploads/hacker.php.2018時,就會被當成PHP腳本執行。
4、文件上傳漏洞的綜合防護
以上例子說明,不可以只通過一種安全手段來阻止攻擊者進行非法文件上傳,應該同時綜合應用檢測文件類型、檢查文件後綴、黑白名單、使用隨機文件名稱等多種方法進行防範。下面的代碼是綜合應用示例。
<?php
/**
* 生成隨機字符串
* @param int $len
* $return string
*/
function genRandomString($len) {
$chars=array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9");
$charsLen=count($chars)-1;
shuffle($chars); // 將精妙絕倫打亂
$output="";
for($i=0;$i<=$len;$i++) {
$output.=$chars[mt_rand(0,$charsLen)];
}
return $output;
}
$whitelist=array(".jpg",".gif","png"); //白名單
$item==substr($_FILES['userfile']['name'],-4);
if(!in_array($item,$whitelist)) {
die("請上傳正確的文件類型");
}
if($_FILES['userfile']['type']!="image/gif") { // 校驗文件MIME類型
die("請上傳正確的文件類型");
}
$uploaddir='/tmp/uploads'; // 將用戶上傳的文件放到項目目錄之外
$uploadfile=$uploaddir.genRandomString(20).$item; // 使用隨機文件名
if(move_uploaded_file($_FILES['userfile']['tmp_name'],$uploadfile)) {
echo "恭喜您,文件上傳成功";
} else {
echo "上傳文件失敗";
}
?>
驗證上傳文件的擴展名,以白名單、黑名單方式為主,但最好使用白名單。
除了在代碼邏輯中防止上傳漏洞外,同時也可以在項目部署時將上傳目錄放到項目工程目錄之外,當作靜態資源文件處理,並且對文件的權限進行設定,禁止文件的執行權限。
當用戶上傳文件到伺服器保存時,一定要使用隨機文件名進行存儲,並保證所存儲的擴展名合法。保證文件名的唯一性,也保證了存儲的安全性,可以防止上傳文件非法擴展進行解析。
微信公眾號:計算機與網絡安全
ID:Computer-network