前言介紹一種比較高端檢測上傳檔案類型的方法,可以防止尾碼名修改等低端的檢測錯誤,有耐心的同學可以參考一下,我會封裝成類供調用MIME類型在把輸出結果傳送到瀏覽器上的時候,瀏覽器必須啟動適當的應用程式來處理這個輸出文檔。這可以通過多種類型MIME(multipurpose internet mail extensions)來完成。在http中,MIME類型被定義在content-type header中。例如,如果用戶端上傳一個excel檔案到伺服器上,那麼這是的mime類型就是“application/vnd.ms-excel”。在php中,可以通過$_FILE["type"]獲得上傳檔案類型。最早的HTTP協議中,並沒有附加的資料類型資訊,所有傳送的資料都被用戶端解釋為HTML文檔,而為了支援多媒體資料類型,HTTP協議中就使用了附加在文檔之前的MIME資料類型資訊來標識資料類型。每個MIME類型由兩部分組成,前面是資料的大類別,後面定義具體的種類。(具體可以查詢mime類型表)
檔案檢測弊端
- 副檔名檢測漏洞(ps:副檔名可以被任意偽造)
- 檔案MIME類型判斷不能使用$_FILES['userfile']['type'](ps:根據PHP官方的文檔說明,該值完全可以被偽造!駭客只需修改瀏覽器的post要求標頭即可繞過這段代碼檢查,進而上傳任意類型的檔案!)
檢測方法(針對excel)
- 通過副檔名判斷是03的excel檔案還是07的excel檔案
- 根據不同的檔案,擷取不同檔案的位元據,和file_signature進行對比,我截了03和07的excel的位元據圖,大家可以參考一下,工具是madedit
- 03的excel
- 07的excel(07可以參考zip檢測)
檢測程式
/** * Detect upload file type * * @param array $file * @return bool $flag */private function detectUploadFileMIME($file) {// 1.through the file extension judgement 03 or 07$flag = 0;$file_array = explode ( ".", $file ["name"] );$file_extension = strtolower ( array_pop ( $file_array ) );// 2.through the binary content to detect the fileswitch ($file_extension) {case "xls" :// 2003 excel$fh = fopen ( $file ["tmp_name"], "rb" );$bin = fread ( $fh, 8 );fclose ( $fh );$strinfo = @unpack ( "C8chars", $bin );$typecode = "";foreach ( $strinfo as $num ) {$typecode .= dechex ( $num );}if ($typecode == "d0cf11e0a1b11ae1") {$flag = 1;}break;case "xlsx" :// 2007 excel$fh = fopen ( $file ["tmp_name"], "rb" );$bin = fread ( $fh, 4 );fclose ( $fh );$strinfo = @unpack ( "C4chars", $bin );$typecode = "";foreach ( $strinfo as $num ) {$typecode .= dechex ( $num );}echo $typecode;if ($typecode == "504b34") {$flag = 1;}break;}// 3.return the flagreturn $flag;}
參考連結檔案類型對照表