C# 檔案存取注意事項 (Path Manipulation 漏洞)

在 C# 中可以這樣組合路徑:
    
var rootPath = @"C:\Users\ruyut\Documents\Projects\ConsoleAppPathTest";
var fileName = "Program.cs";
var path = Path.Combine(rootPath, fileName);
Console.WriteLine(path);

var fullPath = Path.GetFullPath(path);
Console.WriteLine(fullPath);
    

兩個的結果都是:
    
C:\Users\ruyut\Documents\Projects\ConsoleAppPathTest\Program.cs
    

上面的程式碼是假設有一個預設路徑 rootPath ,要在裡面儲存檔案,檔名是變數 fileName ,兩者組合後產生 path ,fullPath 就是這個檔案實際的路徑。

但是如果將 fileName 換成 "../../../Program.cs" ,結果如下:
    
// Path.Combine(rootPath, fileName)
C:\Users\ruyut\Documents\Projects\ConsoleAppPathTest\../../../Program.cs

// Path.GetFullPath(path)
C:\Users\ruyut\Program.cs
    

就會發現明明已經指定預設的路徑(資料夾),但是還是可以存取預設路徑外的其他任何路徑的檔案。
代表將「檔名」交給使用者或是外部控管是有風險的,這就是很常見的 Broken Access Control - Path Manipulation 漏洞。

而要解決也很簡單,只是這個動作在不了解的人面前會看起來很多餘,就是檢查「檔案完整路徑」的開頭和預設路徑是否一致:
    
var rootPath = @"C:\Users\ruyut\Documents\Projects\ConsoleAppPathTest";
var fileName = "../../../Program.cs";
var path = Path.Combine(rootPath, fileName);
Console.WriteLine(path);

var fullPath = Path.GetFullPath(path);
if (!fullPath.StartsWith(rootPath))
    throw new Exception("Invalid path");

Console.WriteLine(fullPath);
    

如果不放心還可以再加上忽略大小寫比對:
    
var rootPath = @"C:\Users\ruyut\Documents\Projects\ConsoleAppPathTest";
var fileName = "../../../Program.cs";
var path = Path.Combine(rootPath, fileName);
Console.WriteLine(path);

var fullPath = Path.GetFullPath(path);
if (!fullPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase))
    throw new Exception("Invalid path");

Console.WriteLine(fullPath);
    

留言

張貼留言

如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com