2010-08-22 80 views
6

我的朋友在我的腳本中發現了一個問題,它提供了對根文件的訪問。PHP安全根

該網址提供了passwd文件:

http://site.com/attachment.php?file=../../../../../../etc/passwd 

如何逃離這個安全漏洞?

+3

*(參考)* HTTP://en.wikipedia。 org/wiki/Directory_traversal – Gordon 2010-08-22 10:18:40

+0

正如@Starx指出的那樣,儘量避免使用文件路徑作爲文檔的標識符(除目錄遍歷外,還有其他問題)。 (@MartIX有關(md5)散列的想法可能有助於精益實施)。此外,這是一個好主意**不要以root身份運行你的服務器。使用一個單獨的用戶,他們只具有系統上完成任務所必需的權限。 – zpea 2012-04-13 21:35:18

+0

(這就是說,如果你的意思是可以訪問root用戶只能讀取的文件,比如'/ etc/shadow',那麼當前Unix中的任何用戶都可以讀取'/ etc/passwd') – zpea 2012-04-13 21:42:14

回答

4

有幾種不同的解決方案。 如果只能有一個文件名,則basename()解決方案將起作用。

然而,如果它可以是路徑,一個更復雜的解決方案是需要

//assume current directory, but can be set anything. Absolute path of course 
$basedir = dirname(__FILE__); 
//assume our files are below document root. 
//Otherwise use it's root dir instead of DOCUMENT_ROOT 
$filename = realpath($_SERVER['DOCUMENT_ROOT'].$_GET['file']); 
if (substr($filename,0,strlen($basedir)) !== $basedir) { 
    header ("HTTP/1.0 403 Forbidden"); 
    exit; 
} 

也有一個有用的PHP配置選項open_basedir

14

不要使用URL字符串下載文件....定義唯一的ID來表示文件而不是路徑。

你可能已經看到像這樣的下載http://www.mysite.com/download.php?id=23423他們做了什麼,使用這個ID,從數據庫中取出文件名和路徑,然後下載它。

1

我想你有一個存放所有附件的目錄。

只需測試文件是否位於您的目錄中。

// http://www.php.net/manual/en/function.basename.php 
// http://cz.php.net/manual/en/function.file-exists.php 
if (file_exists($attachments_path . "/" . basename($_GET['file'])) { 
    // do work 
} 

Starx發佈了一個解決方案,看起來很好。不過,它可以在沒有數據庫的情況下完成。如果有人上傳文件,您可以將該文件存儲爲md5($filename).$extension並使用您的腳本。

+1

附件目錄中有一個名爲「passwd」的文件,代碼還允許下載/ etc/passwd文件?我不是PHP程序員,但我認爲你應該更明確地說要訪問的文件應該以相同的方式形成: $ filename = $ attachments_path。 「/」。基本名($ _ GET [ '文件']) – 2010-08-22 18:01:02