2010-03-03 111 views
32

我有一個Java服務器實現(TFTP,如果你很重要),我想確保它不容易受到路徑遍歷攻擊,允許訪問文件和應該不可用的位置。防禦路徑穿越攻擊的最佳方法是什麼?

在迄今爲止衛冕我的最好的嘗試是拒絕匹配File.isAbsolute()然後依靠File.getCanonicalPath()解決任何.././組件出路徑的任何條目。最後,我確保生成的路徑仍在我的服務器所需的根目錄中:

public String sanitize(final File dir, final String entry) throws IOException { 
    if (entry.length() == 0) { 
     throw new PathTraversalException(entry); 
    } 

    if (new File(entry).isAbsolute()) { 
     throw new PathTraversalException(entry); 
    } 

    final String canonicalDirPath = dir.getCanonicalPath() + File.separator; 
    final String canonicalEntryPath = new File(dir, entry).getCanonicalPath(); 

    if (!canonicalEntryPath.startsWith(canonicalDirPath)) { 
     throw new PathTraversalException(entry); 
    } 

    return canonicalEntryPath.substring(canonicalDirPath.length()); 
} 

是否存在這種未命中的安全問題?有更好/更快的方法可以實現同樣的結果嗎?

代碼需要在Windows和Linux之間一致工作。

+1

不要忘記禁止訪問文件系統中隨處可見的Windows特殊設備(NUL,COM1等)。 – 2010-03-03 23:46:33

+0

好思想希思。以下鏈接似乎有一個Windows的保留文件名的權威列表:http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx – 2010-03-04 00:13:08

+0

爲什麼你不能在你的配置Apache/IIS服務器呢? – kikito 2010-03-04 10:00:14

回答

2

如果你在unix機器上運行它(我不確定windows是否有類似的東西,但它可能),你會想看看chroot。即使你認爲你已經找到了某個人想要查閱的幾個目錄的所有路徑,那麼讓操作系統執行這個事實是很好的。因爲「/」可能是「/ home/me/project」,「/../../ ..」仍然是「/ home/me」 /項目」)

編輯:

有一個chroot系統調用,以及一個chroot命令行工具。我不知道Java是否有本地方法,但是沒有任何東西會阻止你使用命令行工具運行你的服務器。當然,這應該是盡最大努力防止其他路徑操作。

+0

事實上,這不是真的,一個chroot可以用來把一個正在運行的進程放到一個完全獨立的目錄樹與其自己的/ home/var/etc ...在chroot中的目錄遍歷仍然會導致令人討厭的攻擊,甚至是遠程代碼執行。 – rook 2010-03-03 23:50:06

+0

你的第一個陳述是真實的,雖然有些誤導。您可以在子目錄中生成自己的根系統路徑鏡像 - 您需要運行的所有內容,包括Java和相關庫。 第二種說法是強烈的誇張,因爲它通過暗示將chroot與攻擊聯繫起來。如果你有一個可能導致任何攻擊的漏洞,它應該作爲一個單獨的問題修補。 chroot是爲了儘量減少任何潛在安全問題的影響。最後,你不能證明任何代碼是安全的,你只能減少你的攻擊面並減少潛在的破壞。 – Sniggerfardimungus 2010-03-04 19:32:37

1

以下可能會有所幫助。它比較了規範和絕對路徑,如果它們不同,則會失敗。只在mac/linux系統上測試(即沒有窗口)。

這是針對您希望允許用戶提供相對路徑而不是絕對路徑並且不允許任何父目錄引用的情況。

public void failIfDirectoryTraversal(String relativePath) 
{ 
    File file = new File(relativePath); 

    if (file.isAbsolute()) 
    { 
     throw new RuntimeException("Directory traversal attempt - absolute path not allowed"); 
    } 

    String pathUsingCanonical; 
    String pathUsingAbsolute; 
    try 
    { 
     pathUsingCanonical = file.getCanonicalPath(); 
     pathUsingAbsolute = file.getAbsolutePath(); 
    } 
    catch (IOException e) 
    { 
     throw new RuntimeException("Directory traversal attempt?", e); 
    } 


    // Require the absolute path and canonicalized path match. 
    // This is done to avoid directory traversal 
    // attacks, e.g. "1/../2/" 
    if (! pathUsingCanonical.equals(pathUsingAbsolute)) 
    { 
     throw new RuntimeException("Directory traversal attempt?"); 
    } 
} 
相關問題