2011-09-06 52 views
12

我開發了一個php腳本來替換當前的腳本,這將會對各個市場/國家有很大的影響。 其他人之間的腳本提供照片上傳功能。PHP圖像上傳安全方法

經過大量的關於這個問題的閱讀後,我遵循了下面描述的方法。 我將非常感謝您對其安全性的評論。

  1. 該照片上傳到網站根外的私人777文件夾中。
  2. 執行白名單擴展名檢查(只允許jpgs,gifs,pngs)其他所有內容都將被刪除。
  3. 使用getimagesize檢查最小 - 最大尺寸和照片有效性。
  4. 檢查MIME類型和文件擴展名匹配。
  5. 將上傳的照片調整爲標準尺寸(使用imagecopyresampled)。
  6. 將創建的文件保存爲jpg。
  7. 刪除原始文件。
  8. 用新的(不是隨機的名字)保存照片ie img51244.jpg。
  9. 根據不可預測的算法將新照片移動到公用文件夾的變量子目錄(777權限)。即,img10000.jpg將被存儲在photos/a/f/0/img10000.jpgimg10001.jpg將被存儲在photos/0/9/3/img10001.jpg。這是由於其他原因(使用靜態內容服務的子域或使用CDN)完成的。

該腳本將在Linux專用服務器上運行。

+0

這裏沒有東西跳出來。除了文件夾的777權限 - 據我瞭解,如果它有777權限,它不是私有的。但據我所知,只有當你的服務器遭到入侵時,這纔會真正起作用(這至少不會影響我的腳本) – jammypeach

+2

777聽起來並不安全。可能與http://stackoverflow.com/questions/3644138/secure-user-image-upload-capabilities-in-php – ajreal

+0

相關我聽起來很不錯,除非是非常自由的權限。也許他們可能會有所限制?否則,這將盡我所能想到的一切,包括刪除EXIF數據 –

回答

3

您還應該檢查上傳的文件大小,因爲getimagesize有時可能會超過可用的RAM內存。假設你的腳本可能會在任何時候崩潰(例如電力下降)也是很好的,所以你應該執行一些清理程序來刪除剩餘的不需要的文件。

+1

php.ini中已經限制了可上載的最大文件大小。 – Maerlyn

+0

是的,但這並不意味着它足以避免超出內存限制。 –

+0

如果它超過了php.ini中的大小,你不會在'$ _FILES'中得到一個文件名 - 所以你不能檢查它的大小。 – Maerlyn

-1

這是一個相當完整的方法,但我沒有看到任何代碼執行的預防機制。

您應該確保圖像的內容永遠不會被包含(包含或需要調用)或通過eval()執行。

否則,可以執行包含在文件末尾的php代碼。

您也可以嘗試檢測圖像內容中的php代碼(使用file_get_contents,然後搜索例如「<?php」的正則表達式),但我無法找到100%安全的方法來消除可疑代碼而不會破壞一些(有效的)圖像。

+0

我不知道PHP代碼如何在JPG文件中執行,除非您的服務器配置錯誤? –

+0

它沒有意義,因爲很明顯,沒有人會打電話評估或包含在圖像上。我想不出任何人會想到這樣做的場景(除非他剛開始使用PHP)。 –

+0

重新採樣的照片出現後,原始文件即被刪除。 它只按以下順序使用php函數: move_uploaded_file,filesize,getimagesize,imagecreatefromjpeg,imagecopyresampled。 – Alex

4
  1. 根據定義,根據定義,具有chmod 0777的目錄公開給其他登錄到服務器的用戶,而不是私有的。正確的權限將爲700,並由apache(或您的網絡服務器運行的任何用戶)擁有。我不知道爲什麼你不會在這裏使用php的默認臨時目錄,因爲它往往不在web根目錄。
  2. 白名單是一個好主意。注意要有正確的實施。例如,正則表達式/.png/實際上匹配apng.php
  3. 這一步是一個好主意。它基本上檢查文件魔法。
  4. 不是絕對必要的。在前兩個步驟中,我們確定擴展和文件格式是正確的。如果您需要客戶端指定正確的MIME類型,則還應檢查給定的MIME類型和上面確定的MIME類型是否相同。

步驟5到8與安全無關。

第9步:我假設你的網站允許每個人看到每張照片。如果情況並非如此,您應該有一個URL方案,其URL大大延長(比如圖像的哈希)。

+1

(-1)777在網絡可訪問性方面並不意味着公共 - 這就是他所說的。而你的正則表達式的例子暗示,這是任何無論如何...和BTW EXE是一個Windows擴展...: -/ – Raffael

+0

@ Raffael1984我認爲phihag知道這一點。對於*在同一個Web服務器*上的其他用戶的可訪問性,它仍然是公共的,*這是一個問題。但我同意第2步是不必要的,如果你做3)正確 –

+0

@ Raffael1984是真的。我不確定爲什麼這一步是必要的。更新了答案。 – phihag