2014-09-04 86 views
0

我爲我的網站製作了一個簡單的文件管理器腳本。Php scandir限制訪問

爲了列出文件夾中的所有文件和類別,我使用scandir()函數。我有一個包含基本路徑的變量,如$path = /var/www/mysite/uploads。然後我有一個函數,它需要帶有附加路徑的GET變量,如/my/photos/,所以我返回/var/www/mysite/uploads/my/photos的內容。

問題是,如果用戶發送../../../,類似的東西,他會上目錄樹,並將能夠觀看整個系統。

我該如何限制?我唯一一派whas約chroot,但不知道這是什麼,我需要

+0

不要讓用戶有''../在他們的投入,剝離出來,如果他們已經用它 – 2014-09-04 08:40:56

回答

1

您可以使用realpath()

$storagePath = "/var/www/mysite/uploads"; 
$path = $storagePath . $userPath; 

$path = realpath($path); 
if(strpos($path, $storagePath) === 0){ 
    //Path is okay 
    echo "Okay"; 
} 
else { 
    //User wants to gain access into a forbidden area. 
    echo "Danger"; 
} 

Live demo

說明:由用戶提供的路徑與存儲路徑聯繫。然後使用realpath將此路徑轉換爲absolute path。如果絕對路徑從存儲路徑開始,則一切正常,否則不行。

當然,也可以首先針對RegEx運行用戶提供的路徑,以確保路徑只包含有效字符。

+0

你覺得呢http://stackoverflow.com/questions/3661727 /刪除點和斜槓 - 正則表達式非相對這個?使用ltrim?實際上,我編寫了像$ path = $ storagePath這樣的結果路徑。 $ userPath; $ userPath不包含/ var/www/whatever,它只包含像/ my/photos這樣的路徑的一部分。無論如何strpos不會返回true。但不知道如果與ltrim的解決方案是足夠的 – Victor 2014-09-04 09:29:09

+0

@維克特ltrim是肯定的,但我認爲這是不夠的。爲什麼不用'$ storagePath替換上例中的$ _GET [「path」]''。 $ userPath'(或'$ path')。然後它將與'strpos'一起工作,不是嗎? – idmean 2014-09-04 09:31:34

+0

如果我有?path = ../../../../..,那麼結果路徑是/var/www/mysite/uploads/../../../../,strpos返回true,因爲它在一開始會發現/ var/www/mysite/uploads? – Victor 2014-09-04 09:35:30

0

您總是必須驗證用戶輸入!做一個正則表達式來驗證$ _GET ['path']。

此外,您的服務器應該由您的文件系統權限非常低的用戶運行。

0

您必須回答的第一個問題是您爲什麼要從用戶路徑接受。

之後,如果真的需要,您必須保護您的輸入絕對路徑或使用..就可以了。

的東西,如

$project_path = realpath($project_path); 
$realpath = realpath($user_input); 
if (str_pos($realpath, $project_path) !== 0) { 
    throw Exception('Security perimeter violation!'); 
} 
+0

我接受一條路徑,因爲如果用戶想要探索一些他需要的文件夾發送文件夾名稱。如果文件夾包含在其他文件夾中,則會變成'/ my/photos /',所以我給用戶$ path的內容。'/ my/photos /'。我發現你和wumm都使用realpath,感謝你的幫助,看起來正是我需要的 – Victor 2014-09-04 08:51:25

+0

太棒了!看起來很好的理由;) – mcuadros 2014-09-04 08:54:22