PHP文件上傳安全:優(yōu)化代碼有效防范漏洞
說明:任意文件上傳漏洞,很多PHP開發(fā)者也會(huì)做一些簡(jiǎn)單的防護(hù),但是這個(gè)防護(hù)有被繞過的可能。
原生漏洞PHP示例代碼:
$file = $_FILES['file'] ?? []; //檢測(cè)文件類型 $allow_mime = ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']; if(! in_array($file['type'], $allow_mime)) { echo json_encode(['code' => 1, 'msg' => "文件類型錯(cuò)誤"], JSON_UNESCAPED_UNICODE); return; } print_r($file);
上傳一個(gè)PHP文件,提示文件類型錯(cuò)誤,使用ApiPost修改上傳的Content-Type,把原先的application/x-httpd-php修改為image/png,則可繞過。
因?yàn)椋?strong>$_FILES['type']是根據(jù)上傳文件的content-type獲取的,并文件本身的mime-type,而content-type又可以被篡改。
原生漏洞PHP漏洞優(yōu)化意見(獲取臨時(shí)文件的真實(shí)類型):
$file = $_FILES['file'] ?? []; //檢測(cè)文件類型 $allow_mime = ['image/jpg', 'image/jpeg', 'image/png', 'image/gif']; if(! in_array((new \finfo(\FILEINFO_MIME_TYPE))->file($file['tmp_name']), $allow_mime)) { echo json_encode(['code' => 1, 'msg' => "文件類型錯(cuò)誤"], JSON_UNESCAPED_UNICODE); return; } print_r($file);
對(duì)Laravel框架,也有同樣的問題,別用錯(cuò)函數(shù):
$file->getClientMimeType(); //相當(dāng)于$_FILES['file']['type']; $file->getMimeType(); //相當(dāng)于(new \finfo(\FILEINFO_MIME_TYPE))->file($_FILES['file']['tmp_name'])
說話得有依據(jù),經(jīng)過反復(fù)的追Laravel的源碼:
底層對(duì)getClientMimeType()的實(shí)現(xiàn): 是在vendor/symfony/http-foundation/Request.php的createFromGlobals()中,基于$_FILES做的封裝。 底層對(duì)getMimeType()的實(shí)現(xiàn): 是在vendor/symfony/mime/FileinfoMimeTypeGuesser.php的guessMimeType()中,利用finfo的內(nèi)置PHP類實(shí)現(xiàn)的。
對(duì)Laravel任意文件上傳漏洞優(yōu)化意見(獲取臨時(shí)文件的真實(shí)類型):
使用getMimeType函數(shù)。
整體修復(fù)意見:
先判斷文件后綴,在判斷臨時(shí)文件的mime類型屬性,不要根據(jù)請(qǐng)求頭判斷。
擴(kuò)展:
mime_content_type函數(shù)與(new \finfo(\FILEINFO_MIME_TYPE))->file('file_path')的區(qū)別?
檢測(cè)文件mime類型,還有一個(gè)mime_content_type();
- mime_content_type()獲取的mime類型,會(huì)與操作系統(tǒng)的mime類型有映射,意味著不同的系統(tǒng)可能存在一些小差別。
- finfo類使用了 PHP 的 FileInfo 擴(kuò)展。FileInfo 擴(kuò)展利用了文件的特征簽名(或稱為魔術(shù)數(shù)字)來檢測(cè)文件的實(shí)際類型,并根據(jù)文件的內(nèi)容進(jìn)行精確的 MIME 類型推斷。
雖然兩者相差不大,但是推薦用(new \finfo(\FILEINFO_MIME_TYPE))->file('file_path');
(new \finfo(\FILEINFO_MIME_TYPE))->file('file_path')與finfo_file()的區(qū)別?
使用finfo_file()也可以獲取文件的mime類型。
$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file['tmp_name']); $mime = (new \finfo(FILEINFO_MIME_TYPE))->file($file['tmp_name']);
兩者底層對(duì)獲取mime類型的實(shí)現(xiàn)無差別,展示寫法不同。
什么是文件的魔術(shù)數(shù)字?
文件的魔術(shù)數(shù)字是文件頭部的一段特定的字節(jié)序列,用來描述文件的類型或格式,一般用16進(jìn)制表示。
文件的魔術(shù)數(shù)字一般包含一些特殊的字符和數(shù)字組成的固定長(zhǎng)度的字節(jié)串,不同類型的文件具有不同的魔術(shù)數(shù)字。例如,PNG 圖像文件的魔術(shù)數(shù)字為 89 50 4E 47 0D 0A 1A 0A,而 JPG 圖像文件的魔術(shù)數(shù)字為 FF D8 FF E0 00 10 4A 46 49 46 00 01。
PHP獲取魔術(shù)數(shù)字實(shí)現(xiàn)方案:
$fileHandle = fopen($_FILES['file']['tmp_name'], 'rb'); $hex = ''; while (! feof($fileHandle)) { $byte = fread($fileHandle, 1); $hex .= sprintf("%02X ", ord($byte)); } fclose($fileHandle); echo $hex;
到此這篇關(guān)于PHP文件上傳安全:優(yōu)化代碼有效防范漏洞的文章就介紹到這了,更多相關(guān)PHP防止任意文件上傳漏洞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
php將textarea數(shù)據(jù)提交到mysql出現(xiàn)很多空格的解決方法
這篇文章主要介紹了php將textarea數(shù)據(jù)提交到mysql出現(xiàn)很多空格的解決方法,分析了空格出現(xiàn)的原因以及刪除空格的簡(jiǎn)單實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-12-12PHP 雜談《重構(gòu)-改善既有代碼的設(shè)計(jì)》之二 對(duì)象之間搬移特性
承接上文PHP 雜談《重構(gòu)-改善既有代碼的設(shè)計(jì)》之 重新組織你的函數(shù) ,繼續(xù)說重構(gòu)方面的內(nèi)容2012-04-04php中時(shí)間軸開發(fā)(剛剛、5分鐘前、昨天10:23等)
php中時(shí)間軸開發(fā),即顯示為“剛剛”、“5分鐘前”、“昨天10:23”等2011-10-10php 截取GBK文檔某個(gè)位置開始的n個(gè)字符方法
下面小編就為大家?guī)硪黄猵hp 截取GBK文檔某個(gè)位置開始的n個(gè)字符方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03THINKPHP在添加數(shù)據(jù)的時(shí)候獲取主鍵id的值方法
下面小編就為大家?guī)硪黄猅HINKPHP在添加數(shù)據(jù)的時(shí)候獲取主鍵id的值方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04PHP IDE PHPStorm配置支持友好Laravel代碼提示方法
這篇文章主要介紹了PHP IDE PHPStorm配置支持友好Laravel代碼提示方法,重點(diǎn)配置已經(jīng)加紅提示,需要的朋友可以參考下2015-05-05php+MySQL判斷update語句是否執(zhí)行成功的方法
這篇文章主要介紹了php+MySQL判斷update語句是否執(zhí)行成功的方法,可以通過mysql_affected_rows方法加以實(shí)現(xiàn),需要的朋友可以參考下2014-08-08