验证以防止路径字符串上升到父文件夹

Validate to prevent a path string to go up to parent folder

我的业务逻辑正在接受文件夹路径字符串以读取 folder/file。但是,根据安全规定,用户只能访问该文件夹。例如:

他们的文件夹是:C:\foo\user\bar,他们可以通过https://www.example.com/download?path=data/.a.b..txt

访问C:\foo\user\bar\data\.a.b..txt

但是,我想阻止用户输入可能使他们进入文件夹并查看其他人数据的内容。这是我当前的代码:

        var result = this.ResultFolder; // The user folder (\user\bar as in the example)

        if (!string.IsNullOrEmpty(path))
        {
            path = path.Replace("/", @"\");

            if (path.StartsWith(@"\"))
            {
                path = path.Substring(1);
            }

            if (path.StartsWith('\') || path.Contains("..\"))
            {
                throw new InvalidDataException("Forbidden Path.");
            }

            result = Path.Combine(result, path);
        }

基本上,我做的是:

它是正确和安全的吗?有什么框架方法可以帮助解决这个问题吗?

这是一个使用 Path.GetFullPath(string path):

的解决方案

创建此函数:

private static bool VerifyPathUnderRoot(string pathToVerify, string rootPath = ".")
{
    var fullRoot = Path.GetFullPath(rootPath);
    var fullPathToVerify = Path.GetFullPath(pathToVerify);
    return fullPathToVerify.StartsWith(fullRoot);
}

然后你可以用这样的代码来测试它:

 var paths = new[]
 {
     "somepath/somefile.xxx",
     "..\somepath/somefile.xxx",
     @"C:\this\that\the.other",
 };
 foreach (var path in paths)
 {
     var isOk = VerifyPathUnderRoot(path);
     var okString = isOk ? "OK" : "No";
     Debug.WriteLine($"{okString}: {path}");
 }

这会在调试器的“输出”窗格中产生以下结果:

OK: somepath/somefile.xxx
No: ..\somepath/somefile.xx
No: C:\this\that\the.other

我使用 GetFullPath 两次来规范化路径(确保所有斜线都相同,等等)。