程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> php文件上傳漏洞簡單分析

php文件上傳漏洞簡單分析

編輯:關於PHP編程

文件上傳漏洞這個問題不是php中所存在的只是我們用戶在程序開發時可能做得不夠好所導致的,以前的asp同樣也存在文件上傳漏洞,下面我來給大家介紹php文件上傳漏洞簡單分析與解決辦法。


下面是一個簡單的文件上傳表單

 代碼如下 復制代碼

<form action="upload.php" method="post" enctype="multipart/form-data" name="form1">
  <input type="file" name="file1" /><br />
  <input type="submit" value="上傳文件" />
  <input type="hidden" name="MAX_FILE_SIZE" value="1024" />
</form>

php的配置文件php.ini,其中選項upload_max_filesize指定允許上傳的文件大小,默認是2M

$_FILES數組變量

PHP使用變量$_FILES來上傳文件,$_FILES是一個數組。如果上傳test.txt,那麼$_FILES數組的內容為:

 代碼如下 復制代碼

$FILES

Array

{

        [file] => Array

        {

                [name] => test.txt                //文件名稱

                [type] => text/plain                //MIME類型

                [tmp_name] => /tmp/php5D.tmp        //臨時文件

                [error] => 0                //錯誤信息

                [size] => 536                //文件大小,單位字節

        }

}

如果上傳文件按鈕的name屬性值為file

 代碼如下 復制代碼

<input type="file" name="file" />

那麼使用$_FILES['file']['name']來獲得客戶端上傳文件名稱,不包含路徑。使用$_FILES['file']['tmp_name']來獲得服務端保存上傳文件的臨時文件路徑

存放上傳文件的文件夾

PHP不會直接將上傳文件放到網站根目錄中,而是保存為一個臨時文件,名稱就是$_FILES['file']['tmp_name']的值,開發者必須把這個臨時文件復制到存放的網站文件夾中。

$_FILES['file']['tmp_name']的值是由PHP設置的,與文件原始名稱不一樣,開發者必須使用$_FILES['file']['name']來取得上傳文件的原始名稱。

上傳文件時的錯誤信息

$_FILES['file']['error']變量用來保存上傳文件時的錯誤信息,它的值如下:

錯誤信息 數值 說    明
UPLOAD_ERR_OK 0 沒有錯誤
UPLOAD_ERR_INI_SIZE 1 上傳文件的大小超過php.ini的設置
UPLOAD_ERR_FROM_SIZE 2 上傳文件的大小超過HTML表單中MAX_FILE_SIZE的值
UPLOAD_ERR_PARTIAL 3 只上傳部分的文件
UPLOAD_ERR_NO_FILE 4 沒有文件上傳

文件上傳漏洞

如果提供給網站訪問者上傳圖片的功能,那必須小心訪問者上傳的實際可能不是圖片,而是可以指定的PHP程序。如果存放圖片的目錄是一個開放的文件夾,則入侵者就可以遠程執行上傳的PHP文件來進行攻擊。

下面是一個簡單的文件上傳例子:

 代碼如下 復制代碼

<?php
// 設置上傳文件的目錄
$uploaddir = "D:/www/images/";

// 檢查file是否存在
if (isset($_FILES['file1']))
{
 // 要放在網站目錄中的完整路徑,包含文件名
    $uploadfile = $uploaddir . $_FILES['file1']['name'];
 // 將服務器存放的路徑,移動到真實文件名
 move_uploaded_file($_FILES['file1']['tmp_name'], $uploadfile);
}
?>
……
<form method="post" enctype="multipart/form-data" name="form1">
  <input type="file" name="file1" /><br />
  <input type="submit" value="上傳文件" />
  <input type="hidden" name="MAX_FILE_SIZE" value="1024" />
</form>

這個例子沒有檢驗文件後綴,可以上傳任意文件,很明顯的上傳漏洞,要解決上面的問題很簡單,我們從一段代碼來看。

 代碼如下 復制代碼  switch( $extension )
   {
    case 'application/msword':
    $extension ='doc';
    break;
    case 'application/vnd.ms-excel':
    $extension ='xls';
    break;
    case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
    $extension ='docx';
    break;
    case 'application/vnd.ms-powerpoint':
    $extension ='ppt';
    break;
    case 'application/pdf':
    $extension ='pdf';
    break;
    case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
    $extension ='xlsx';
    break;
    default:
    die('只允許上傳doc,docx,xls,pdf,ppt文件 <a href="wend.php">重新上傳</a>');
   
   }

這個是用來限制用戶上傳的類型號或後綴名了,這樣可以過濾簡單不能直接上傳php了,但是我們再看一個實例,你繪發現太可怕了。

用畫圖工具新建一個jpg或gif或png之類圖片格式,開頭一定是GIF或JPG或PNG之類。

將php網馬的頭部寫入GIF 如圖:

 代碼如下 復制代碼


然後寫一個簡單的php上傳文件處理(我趕時間隨便寫的,沒什麼美感):

 

<?php

if($_FILES){
 echo '以下是錯誤的$_FILES:<br/>';
 echo "<pre>";
 print_r($_FILES);
 echo "</pre>";

 echo "以下是錯誤的getimagesize()<br/>";
 echo "<pre>";
 print_r(getimagesize($_FILES['bug']['tmp_name']));
 echo "</pre>";
 exit;
 $fp = fopen($_FILES['bug']['tmp_name'],"r");
 $content = fread($fp,filesize ($_FILES['bug']['tmp_name']));
 //echo $content 可以看到上傳的源代碼
}
?>

<form action="" method="post" enctype="multipart/form-data">

<input type="file" name="bug" />

<input type="submit" >
</form>

就可以看到如圖這樣坑爹的效果了。


首先是print_r($_FILES) 直接顯示的是擴展的jpg結果。
然後是php函數getimagesize()的結果是gif(它以文件開頭那段為判斷依據)。

在這種問題上php是無法解決的,但我們可以從服務器目錄權限來操作,下面提供一些解決辦。

其實,我們抓住幾個地方即可,我們先來分析下,既然用戶要上存文件,而且文件將是多種多樣格式;可能有的文件內容與用戶傳入格式不一致,有的文件內容還夾雜木馬代碼。 那麼,我們讓用戶上存文件,跟站點文件做一個分別授權,做隔離。

讓保存上存目錄獨立開來,目錄權限只讀不能執行
這一步從系統設計加以授權,無論你上次什麼文件,都不可能執行到。就算我不做任何檢測,你的文件都上存到這裡了,也不會對我系統構成安全。(如果有用戶上存一些反動言語的圖片,那另外需要處理的)

 

不直接使用服務器傳入值,所有都要進行檢測

這類跟我們做一切輸入都是有害原則一樣,對於客戶端傳入的:type, name ,都要進行判斷,不直接使用。對於要生成到某個目錄,某個文件名。

文件名最好方法是:自己寫死目錄(不要讀取傳入目錄),文件名,最好自己隨機生成,不讀取用戶文件名。文件擴展名,可以取最右邊"."後面字符。

以上2個方法,剛好從2個方面對上存做了整體約束。

方法2 : 保存上存文件名,按照自己指定目錄寫入,並且文件名自己生成的。

方法1:只要保證文件寫對了位置,然後從配置上,對寫入目錄進行權限控制,這個是治本。可以做到,你無論上存什麼文件,都讓你沒有權限跳出去可以運行。

 

以上2個方法,一起使用,可以保證文件正確存到地方,然後,權限可以控制。 這裡順便說明下, 判斷用戶上存文件是否滿足要求類型,就直接檢查文件擴展名,只要滿足擴展名就讓上存。 反正,做了執行權限限制,你不按要求上存內容,也無妨。 反正,不能執行,也不會有多大危害性的。

正確步驟:
1.讀取文件名,驗證擴展名是不是在范圍內

2.自己定義生成的文件名,目錄,擴展名可以來自文件名擴展名。 其它值,都自己配置,不讀取上存中內容

3.將文件 移到新目錄(這個目錄權限設置只讀)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved