2013-10-18 45 views
4

考慮以下經典問題的情況下:dirname是否足以防止目錄遍歷攻擊?

<?php 
$filename = "/tmp/".$_GET['f']; 
readfile($filename); 

此代碼是易受directory traversal attack,例如,如果的$_GET['f']值爲../etc/shadow的該文件的內容將被公開給攻擊者。

有一些衆所周知的方法來防止這種類型的攻擊;我不問如何做到這一點。問題是:以下是用dirname防彈的方法來防止這種攻擊嗎?

<?php 
if (dirname($_GET['f']) != '.') die ('Attack prevented'); 

聽起來像它應該是因爲dirname

  • 回報.,當且僅當在輸入路徑中沒有斜槓(在線文檔,使一個不太嚴格的保證,但the source是明確的)
  • 是二進制安全的(所以不能被嵌入的空值欺騙)

所以,據我所知道的,攻擊的唯一可能的途徑將是在編碼數據$_GET['f']通過這樣,要麼性格/\(讓我們不要忘記的Windows)編碼的東西,不包含相應的字符的ASCII值必須同時被底層C運行時庫的fopen函數透明地支持。

無ASCII值限制排除了所有的單字節編碼,UTF-8和UTF-16的兩種風格;此外,由於C運行時的規範與平臺無關,因此攻擊只能適用於某些使用「易受攻擊」編碼來表示名稱的文件系統。據我所知,這種文件系統並不存在;任何人都難以創造它;最後PHP不會託管在這樣一個假設的外來系統上,即使它存在。

總之,在我看來,這個檢查 100%安全。有什麼我錯過了嗎?

+0

我用的代碼從這個【答案】(http://stackoverflow.com/a/4205278/453348),你也可以從這個問題 – tttony

+0

@tttony檢查'MainMa'回答:謝謝,但正如我上面所說的,我知道如何防止這種攻擊。問題是,它可以自信地防止*這種方式*? – Jon

+0

根據我的測試,你的方法工作,看起來很簡單,但它的工作 – tttony

回答

1

我不確定我是否會聲稱某件東西是100%安全的。也就是說,我想不出一個明顯的情況,這將是不安全的,我嘗試了很多排列組合。也就是說,你需要添加一個$ _GET ['f']不是空的檢查。使用上面的代碼訪問一個頁面,沒有f的值給了我「防止攻擊」的消息,這可能不是預期的效果。

<?php 
if (!empty($_GET['f']) && dirname($_GET['f']) != '.') die ('Attack prevented'); 
+0

當然,這些例子包含最低限度的代碼來說明。你嘗試過什麼樣的排列? – Jon

+0

我創建了一個1級的文件,並以我想到的引用該文件的所有可能的方式輸入(即?f = ../test.txt?f = .. \ test.txt?f = ..%2Ftest。 txt?f =/test.txt?f =%2Ftest.txt?f = asdf)列表繼續。只有腳本真正本地的文件路徑纔會拋出錯誤。再次,我討厭使用「100%安全」,但我無法找到明顯的東西來克服這一點。 –