php 上傳excel時,excel mime-type類型爲application/octet-stream,沒法經過驗證

問題

在某個客戶的電腦上上傳excel時,mime-type類型爲application/octet-stream 沒法經過後臺驗證,但在咱們的電腦上能夠

交互流程

用戶使用wps建立文件保存格式,每一個不一樣的文件都擁有不一樣的mime-type,而此時mime-type爲 application/octet-stream ->用戶上傳excel->瀏覽器獲取文件mime-type 並在請求體中傳遞Content-Type: 瀏覽器獲取的mime-type->傳遞到服務器並驗證文件的mime-type->不經過,返回錯誤給前端
clipboard.png

猜想緣由

1.可能wps的某個版本將excel的mime-type類型保存爲 application/octet-stream 或者其餘類型,當瀏覽器遇到沒法識別的類型時,也默認爲 application/octet-stream,而在咱們的電腦上,wps版本較新,保存的文件mime-type爲 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
2.咱們在後臺驗證mime-type的合法性時,通常都會這樣驗證:
'application/vnd.ms-excel',
        'application/vnd.ms-excel',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3.而thinkphp5在獲取上傳文件時,檢測上傳文件的type 是根據瀏覽器傳遞過來的,這樣就會形成一些問題,因此驗證沒法經過,也多是更嚴重的 文件上傳漏洞
參考連接: MIME

上傳文件mime類型僞造測試(文件上傳漏洞)

工具: fiddler
代碼:
<?php

$allowExcelMimeType = [
    'application/vnd.ms-excel',
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
];

$allowExcelExt = [
     'xls', 'xlsx',
];

$fileInfo = $_FILES['fieldNameHere'];

$pos = mb_strripos($fileInfo['name'], '.', 0, 'utf8');
$ext = mb_substr($fileInfo['name'], $pos + 1);
$destination = md5(time()) . '.' . $ext;

move_uploaded_file($fileInfo['tmp_name'], $destination);
var_dump($fileInfo);

$mimeType = mime_content_type($destination);
echo '文件類型:'.$mimeType.PHP_EOL;

if (!in_array($ext, $allowExcelExt, true) || !in_array($fileInfo['type'], $allowExcelMimeType, true)) {
    echo '非法的文件類型:'.$mimeType.PHP_EOL;
    exit();
}

echo '上傳成功';
excel正常上傳返回數據:

clipboard.png

D:\3_tools\wamp\www\test-some\16.upload.php:22:
array (size=5)
  'name' => string 'test.xlsx' (length=9)
  'type' => string 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' (length=65)
  'tmp_name' => string 'D:\3_tools\wamp\tmp\php6F55.tmp' (length=31)
  'error' => int 0
  'size' => int 17300

文件類型:application/octet-stream 上傳成功
excel 文件僞造mime-type:
clipboard.png
D:\3_tools\wamp\www\test-some\16.upload.php:22:
array (size=5)
  'name' => string 'test.xlsx' (length=9)
  'type' => string 'application/so-cool' (length=19)
  'tmp_name' => string 'D:\3_tools\wamp\tmp\php2008.tmp' (length=31)
  'error' => int 0
  'size' => int 17300

文件類型:application/octet-stream 非法的文件類型:application/octet-stream
僞造php文件mime-type,建立一個php文件,將後綴改成xlsx
clipboard.png
D:\3_tools\wamp\www\test-some\16.upload.php:22:
array (size=5)
  'name' => string 'test.php.xlsx' (length=13)
  'type' => string 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' (length=65)
  'tmp_name' => string 'D:\3_tools\wamp\tmp\php133E.tmp' (length=31)
  'error' => int 0
  'size' => int 17

文件類型:text/x-php 上傳成功

總結

利用這個漏洞,咱們能夠跳過一些檢測不嚴格的文件上傳,上傳一些很差的代碼帶服務器並執行

解決方案

在php中有獲取文件mime-type的函數 finfomime_content_type

問題及拓展

1.文件的類型的二進制約定方式(查找RFC)
2.瀏覽器怎麼獲取文件的mimet-type

參考

阮一峯-mime-type
mime-type
文件上傳
瀏覽器獲取mime-type
相關文章
相關標籤/搜索