Reputation: 20648
My business logic is accepting a folder path string to read a folder/file. However as security dictates, the user can only access that folder. For example:
Their folder is: C:\foo\user\bar, they can access C:\foo\user\bar\data\.a.b..txt
by https://www.example.com/download?path=data/.a.b..txt
However, I want to prevent user from entering something that could make them go up a folder and see data of other. Here is my current code:
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);
}
Basically, what I do:
Replace all / into \ so I only have to worry about one separation character.
The request allows path to start with \ , it counts as nothing.
Now if user try to be malicious (by using \\
to go to root directory), or trying to go up a level by using ..\
(note before I used ..
only, but get false case because it is valid file/folder name)
Is it correct and safe yet? Is there any framework method that helps with this?
Upvotes: 2
Views: 1016
Reputation: 7111
Here's a solution that uses Path.GetFullPath(string path)
:
Create this function:
private static bool VerifyPathUnderRoot(string pathToVerify, string rootPath = ".")
{
var fullRoot = Path.GetFullPath(rootPath);
var fullPathToVerify = Path.GetFullPath(pathToVerify);
return fullPathToVerify.StartsWith(fullRoot);
}
Then you can test it with code like this:
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}");
}
which results in this in the Output pane of the debugger:
OK: somepath/somefile.xxx
No: ..\somepath/somefile.xx
No: C:\this\that\the.other
I use GetFullPath
twice to canonicalize the paths (making sure that all slashes end up the same, etc.).
Upvotes: 2