為什麼檔案上傳表單是主要的安全威脅

oschina發表於2013-09-13

  為了讓終端使用者將檔案上傳到您的網站,就像是給危及您的伺服器的惡意使用者開啟了另一扇門。即便如此,在今天的現代網際網路的Web應用程式,它是一種常見的要求,因為它有助於提高您的業務效率。在Facebook和Twitter等社交網路的Web應用程式,允許檔案上傳。也讓他們在部落格,論壇,電子銀行網站,YouTube和企業支援門戶,給機會給終端使用者與企業員工有效地共享檔案。允許使用者上傳圖片,視訊,頭像和許多其他型別的檔案。 向終端使用者提供的功能越多,Web應用受到攻擊的風險和機會就越大,這種功能會被惡意使用者利用,獲得到一個特定網站的許可權,或危及伺服器的可能性是非常高的。

  當在測試幾個Web應用程式時,我們注意到,相當多的知名Web應用程式,不具備安全的檔案上傳形式。這些漏洞很容易被利用,我們可以訪問這些Web應用程式的伺服器託管到檔案系統。在這篇文章中,我們為您介紹8種常見的方式,我們遇到過的安全檔案上傳表單。同時,還將展示一個惡意的使用者,可以輕鬆地繞過這些安全措施。

  案例1:沒有任何驗證的簡單檔案上傳表單

  一個簡單的檔案上傳表單通常包含一個HTML表單和PHP指令碼。 HTML表單的形式呈現給使用者,而需要檔案上傳功能的PHP指令碼中包含的程式碼。這種形式和PHP指令碼下面是一個例子:

  HTML Form:

<form enctype="multipart/form-data" action="uploader.php" method="POST"> 
<input type="hidden" name="MAX_FILE_SIZE" value="100000" /> 
Choose a file to upload: <input name="uploadedfile" type="file" /><br /> 
<input type="submit" value="Upload File" /> 
</form>

  PHP Code:

<?php
    $target_path  =  "uploads/";
    $target_path  =  $target_path  .  basename($_FILES['uploadedfile']['name']);
    if (move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
    echo "The file " . basename($_FILES['uploadedfile']['name']) . " has been uploaded";
    } else {
    echo "There was an error uploading the file, please try again!";
    }
?>

  當PHP接收POST請求且編碼型別是multipart/form-data,它會建立一個臨時檔名隨機的臨時目錄中(例如/ var/tmp/php6yXOVs)。 PHP也將填充全域性陣列$_FILES上傳的檔案的資訊:

  $ _FILES ['UploadedFile的'] ['名稱']:在客戶機上的檔案的原始名稱

  $ _FILES ['UploadedFile的'] ['型別']:檔案的MIME型別

  $ _FILES ['UploadedFile的'] ['大小']:檔案的大小(以位元組為單位)

  $_FILES ['UploadedFile的']['不對tmp_name']:上傳的檔案儲存在伺服器上的臨時檔名。

  PHP函式move_uploaded_file將使用者提供的臨時檔案移動到一個位置。在這種情況下,目的地是伺服器根目錄以下。因此,檔案可以使用的URL,如:http://www.domain.tld/uploads/uploadedfile.ext訪問。在這個簡單的例子中,有允許上傳的檔案型別沒有限制,因此攻擊者可以上傳一個PHP或NET帶有惡意程式碼的檔案,可導致伺服器妥協。

  這可能看起來像很幼稚的例子,但我們在一些Web應用中沒有遇到這樣的程式碼。

  案例2:Mime型別驗證

  另一個常見的錯誤Web開發人員確保檔案上傳表單時,只檢查從PHP返回mime型別。當一個檔案被上傳到伺服器,PHP將設定變數$_FILES['UploadedFile']['type']所提供的Web瀏覽器客戶端使用的MIME型別。然而,檔案上傳表單驗證不能依賴於這個值。惡意使用者可以輕鬆地使用指令碼或其他一些自動化的應用程式,允許傳送HTTP POST請求,這讓他送一個假的mime型別的檔案上傳。

  案例3:限制危險的擴充

  在另一個例子裡,我們遇到了檔案上傳使用黑名單的做法,作為一項安全措施。從開發者收集制定的危險列表,如果正在上傳的檔案包含在列表中,訪問會被拒絕。

  使用危險的副檔名,其主要缺點之一是,它幾乎不可能編制一份完整的清單,包括攻擊者可以使用的所有可能的副檔名。例如如果程式碼執行在託管環境中,通常這樣的環境讓大量的指令碼語言,如Perl,Python和Ruby等,列表可以是無窮無盡的。

  惡意使用者可以很容易地繞過該檢查上傳一個檔名為“.htaccess”,其中包含類似於下面的一行程式碼:

  AddType application/x-httpd-php .jpg

  上面的程式碼行,指示Apache Web伺服器執行jpg圖片,好像他們是PHP指令碼。攻擊者現在可以上傳一個jpg副檔名的檔案,其中包含PHP程式碼。正如下面的截圖,通過web瀏覽器請求一個jpg檔案,其中包含PHP的命令phpinfo()函式,它仍然是從Web伺服器執行:

Why File Upload Forms are a Security Threat

  案例4: 雙副檔名 (第1部分)

  本案例中使用的安全策略和案例3中所使用的非常相近. 儘管方式換成了簡單的檢查檔名具有的副檔名, 開發者通過在檔名中查詢 ‘.’ 字元並提取點號之後的字串來得到副檔名.

  繞過該途徑的方法有點兒複雜, 但是仍然是現實的. 首先, 讓我們看看 Apache 是怎麼處理具有多重副檔名的檔案的. Apache 手冊中有如下一段陳述:

“檔案可以有多個副檔名, 這些副檔名的順序一般情況下是無關緊要的. 例如: 如果檔案 welcome.html.fr 被對映為內容型別是 text/html , 語言是法語的話, 檔案welcome.fr.html 將被對映為完全相同的內容. 如果一個以上的副檔名對映到同種型別的元資訊上, 那麼將使用最右邊的那個, 除了語言和內容編碼. 比如: .gif 的 MIME 型別是 image/gif , .html 的 MIME 型別是 text/html , 那麼 welcome.gif.html 的 MIME 型別將是text/html ."

  因此一個名為 ‘filename.php.123’ 的檔案將會被解釋為一個 PHP 檔案並被執行. 這僅限於最後的那個副檔名(本例中是 .123)沒有在 web 伺服器的 mime-types 列表中被指定. web開發者通常不會意識到 Apache 還存在這麼一個 ‘特性’, 出於某些原因來說這可能非常危險. 知道了這個以後, 一個攻擊者可以上傳一個名為 shell.php.123 的檔案並繞過檔案上傳保護機制. 後臺指令碼將會計算出最後的副檔名 (.123)並作出該副檔名並不在危險的副檔名列表內的結論. 話雖如此, 想要預防某惡意使用者可能會使用的所有隨機副檔名來上傳一個檔案到你的 web 伺服器上是不可能的.

  案例5: 雙副檔名 (第2部分)

  一個更好的增強檔案上傳表單的安全性的途徑就是白名單機制. 在本例中, 開發者定義了一個 已知/可接受 的副檔名列表並且不允許使用未在名單中指定的副檔名.

  然而, 在某些情況下該途徑不會像期待的方式那樣工作. 當 Apache 被配置為執行 PHP 程式碼的時候, 存在兩種方式來實現該機制: 使用 AddHandler 指令, 或者使用 AddType 指令. 如果 AddHandler 指令被使用, 所有包含 ‘.php’ 副檔名的檔名(例如: ‘.php’ , ‘.php.jpg’)均被作為 PHP 指令碼來執行. 因此, 如果你的 Apache 配置檔案包含如下一行的話, 你可能很容易受到攻擊:

  AddHandler php5-script .php

  一個攻擊者可以上傳名為 ‘filename.php.jpg’ 的檔案並繞過保護機制, 然後執行其中的程式碼.

  案例 6: 檢查圖片頭部

  當僅允許上傳圖片的時候, 開發者通常使用 PHP 的 getimagesize 函式來檢測圖片的頭部資訊. 該函式在被呼叫時將會返回圖片的尺寸, 如果圖片經驗證為無效的, 也就是說圖片頭部資訊不正確, 則會返回 false 值. 因此一個開發者一般會檢查該函式是否返回 true 或 false, 並且通過該資訊來驗證上傳的檔案. 所以, 如果一個惡意使用者試著上傳一個內嵌有簡單 PHP shell 的 jpg 檔案的話, 該函式會返回 false 然後他將不允許上傳此檔案. 然而, 即使這種方式也能被很容易的繞過. 如果一個圖片在一個圖片編輯器內開啟, 就如 Gimp, 使用者就可以編輯圖片的註釋區, 那兒就能插入 PHP 程式碼, 就如下圖所示.

  該圖片仍然有一個有效的頭部; 因此就繞過了 getimagesize 函式的檢查. 從下面截圖中可以看到, 當一個普通的 web 瀏覽器請求該圖的時候, 插入到圖片註釋區的 PHP 程式碼仍然被執行了:

  案例七:通過.htaccess保護上傳資料夾

  另一種流行的穿件安全的檔案上傳表單的方法是適用.htaccess保護好上傳檔案存放的資料夾。辦法是限制這個資料夾裡的指令碼檔案的執行。這種情形一下,一個.htaccess檔案一般包含下面的程式碼:

  AddHandler cgi-script .php .php3 .php4 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi
  Options –ExecCGI

  上面的是另一種形式的黑名單,本身並不是很安全。在PHP手冊中,move_uploaded_file一章中,有一個warning:若目標檔案已經存在,則會覆蓋原檔案。

  因為上傳的檔案能夠而且會覆蓋已經存在的同名檔案,一個惡意使用者很輕易就能用他自己修改過的.htaccess替換掉原來的。這使得他可以執行特定的將會幫助他危害伺服器的指令碼。

  案例八:客戶端驗證

  另一種在檔案上傳表單中常用的安全技術是在客戶端驗證上傳的檔案。一般而言,該技術在ASP.NET應用中更通用一些,因為ASP.NET提供了易用的驗證控制元件。

  這些驗證控制元件允許開發者對要上傳的檔案做正則檢查,以查出待上傳的副檔名是否在允許列表中。下面是一段來自微軟網站的示例程式碼:

  <asp:FileUpload ID="FileUpload1" runat="server" />
     
    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Upload File" />&nbsp;
     
    <asp:Label ID="Label1" runat="server"></asp:Label>
    <asp:RegularExpressionValidator id="RegularExpressionValidator1" runat="server"
    ErrorMessage="Only mp3, m3u or mpeg files are allowed!"
    ValidationExpression="^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w].*))
    +(.mp3|.MP3|.mpeg|.MPEG|.m3u|.M3U)$" ControlToValidate="FileUpload1"></asp:RegularExpressionValidator>
     
    <asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server"
    ErrorMessage="This is a required field!"
    ControlToValidate="FileUpload1"></asp:RequiredFieldValidator>
    &nbsp;

  這段ASP.NET程式碼使用了驗證控制元件,所以終端使用者只被允許上傳.mp3,.mpeg,或者.m3u檔案到伺服器。若檔案型別和這三個指定的檔案型別不一致,驗證控制元件將跑出異常,檔案也就不會被上傳。

  由於這種檔案驗證是在客戶端完成的,惡意使用者很容易就能繞過這一檢查。寫一段客戶端指令碼來替換web應用的驗證指令碼做驗證並非不可能。不用web瀏覽器,入侵者可以使用可以傳送HTTP POST請求的程式來實現上傳檔案。

  推薦的解決方案

  在允許上傳檔案的網站和web應用中,應當應用下面的一系列最佳實踐方法。這些實踐方法將有助於你保證web應用的上傳檔案的安全性。

  • 定義一個.htaccess檔案,只允許訪問指定副檔名的檔案。
  • 不要把.htaccess檔案和上傳檔案放在同一個目錄裡,應該放在父目錄裡。
  • 一個典型的只允許 gif, jpg, jpeg 和 png檔案的.htaccess檔案應當包含下面的程式碼(根據你的需求做調整)。這樣也能阻止雙副檔名攻擊。
deny from all
<Files ~ "^\w+\.(gif|jpe?g|png)$">
order deny,allow
allow from all
</Files>
  • 如果可能,把檔案上傳到root目錄以外的目錄裡。
  • 禁止覆蓋已存在的檔案(以阻止.htaccess覆蓋攻擊)
  • 建立一個mime-type白名單列表。(只允許這個列表裡的Mime-type)
  • 生成一個隨機的檔名,並且加上此前生成的副檔名、
  • 不要只依賴客戶端驗證,這不夠。理想的是既有客戶端驗證也有伺服器端驗證。

  總結

  如上所述,惡意使用者有很多手段繞過檔案上傳表單安全驗證。因此,在web應用中實現檔案上傳表單時,應當尊徐正確的安全指導,並且做恰當的測試。不幸的是要做足夠的測試將會需要很多時間和更多的安全專家。

  還好有了Acunetix WVS,不需要安全專家就可以自動完成上傳表單脆弱性檢查,Acunetix WVS用最少的時間為開發者提供了足夠多的能夠追蹤並修復問題的資訊。

  原文地址:http://www.acunetix.com/websitesecurity/upload-forms-threat/

相關文章