验证以防止路径字符串上升到父文件夹
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以\开头,不算什么
现在,如果用户试图恶意(通过使用 \
进入根目录),或试图通过使用 ..\
升级(注意在我之前仅使用 ..
,但得到错误的大小写,因为它是有效的 file/folder name)
它是正确和安全的吗?有什么框架方法可以帮助解决这个问题吗?
这是一个使用 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
两次来规范化路径(确保所有斜线都相同,等等)。
我的业务逻辑正在接受文件夹路径字符串以读取 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以\开头,不算什么
现在,如果用户试图恶意(通过使用
\
进入根目录),或试图通过使用..\
升级(注意在我之前仅使用..
,但得到错误的大小写,因为它是有效的 file/folder name)
它是正确和安全的吗?有什么框架方法可以帮助解决这个问题吗?
这是一个使用 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
两次来规范化路径(确保所有斜线都相同,等等)。