2010-06-08 139 views
3

我有一個php腳本,它通過$_GET獲取相對路徑名,讀取該文件並創建它的縮略圖。我不希望用戶能夠從服務器讀取任何文件。只有來自某個目錄的文件應該被允許,否則劇本應該exit()

這裏是我的文件夾結構:

files/ <-- all files from this folder are public 
my_stuff/ <-- this is the folder of my script that reads the files 

我的腳本通過mydomain.com/my_stuff/script.php?pathname=files/some.jpg訪問。什麼不應該被允許e。摹:mydomain.com/my_stuff/script.php?pathname=files/../db_login.php

所以,這裏是腳本的文件夾my_stuff相關部分:

... 
$pathname = $_GET['pathname']; 
$pathname = realpath('../' . $_GET['pathname']); 

if(strpos($pathname, '/files/') === false) exit('Error'); 
... 

我真的不知道有關的做法,似乎並不對我來說是安全的。任何人有更好的主意?

回答

2

這個怎麼樣(它處理的情況下,當你移動的服務器,因爲沒有硬編碼絕對路徑):

$pathname = realpath('../' . $_GET['pathname']); 
$rootpath = realpath('../files/'); 

if (strpos($pathname, $rootpath) !== 0) exit('Error'); 
3

我會先做一個realpath()(解析任何「../」和其他引用),然後檢查結果是否是允許的子目錄。

以你的情況(我不明白爲什麼你需要使用的文件/在這種情況下,如果它是被允許的唯一目錄,但無論如何):

$basedir = "/etc/www"; 
$allowed = "/etc/www/files"; 

$pathname = realpath($basedir."/".$_GET["pathname"]); 

if (!$pathname) 
die ("Unknown file path"); 

// Check whether $pathname begins with $allowed (= is a sub-directory) 
if (substring($pathname, 0, strlen($allowed)) != $allowed) 
die ("illegal access!"); 

據我所看到的,這應該是一個安全的方法。

+0

任何想法如何以編程方式設置$ basedir和$允許腳本在具有不同路徑的不同服務器之間移植? – Max 2010-06-08 13:26:42

+0

@Max啊歡迎來到我的回答:) – 2010-06-08 13:27:21

0

我已經這樣做過
basedir被定義爲腳本所在的目錄。

$basedir=dirname(__FILE__)."/"; 
$systemdir=realpath($_SERVER['DOCUMENT_ROOT'].$dir)."/"; 
if (substr($systemdir,0,strlen($basedir)) !== $basedir) { 

...但佩卡是快:)

+1

唯一要注意的是,不同的實現(FastCGI,mod_php,前端服務器等)對待DOCUMENT_ROOT的方式不同。如果這是一次性腳本,它可能不是問題。但如果這是別人將要使用的東西,不要依賴它... – ircmaxell 2010-06-08 13:58:40

+0

好點我一直忘記它 – 2010-06-08 14:17:27

0

我也將檢查./../$_GET['pathname']中的存在,因爲這些將是他們不應該去的地方的明顯嘗試。確實realpath使它安全(因爲...是「已解決」),但strpos檢查可能在某些(可能是越野車)情況下很弱,其中/files/字符串可能稍後出現,但在訪問實際文件時將被忽略,例如一個假想的技巧,比如

/site/my_stuf/secretfile.txt /files/

(使用這樣的字符串來訪問一個文件應該「看」,即「secretfile.txt」(包括空格)是不是一個目錄名,一切都應該失敗......但正如所說,這個假設可能是在一個錯誤的情況下真實的,如果這些技巧利用其他一些不太假設的錯誤...當然這是不知道的util它被利用)

所以我重複我的建議,特別是檢查../ GET字符串;並且爲什麼不將這個字符串解釋爲從files開始的路徑,即,將files/預加載到用戶提供的任何內容,並且如已經說過的那樣避免存在../

我不知道是否所有這些都是偏執的(或更好的解決方案存在),但我已經使用了類似的方法爲基於URL的目錄/文件列表,它允許「直接」訪問站點的子目錄我的,我當然想要確保沒有辦法擺脫那個目錄。

0

注意:使用實時路徑提供的答案是可以的,但是他們應該提到實際路徑在所有服務器變體中的工作方式都不一樣。