I have a rootPath
that I trust and a relativePath
that I don't. I want to combine them in such a way that I can be sure that the result is under rootPath
and that the user can't use ..
to get back past the starting point. I do want the relative path to allow things like: hello\..\world
== world
views:
257answers:
3One thing you can do is to count the number of backslashes (\
) and double-dots (..
), and make sure that the number of double-dots is smaller than the number of backslashes. In order to go above the rootPath
in your folder structure, you'll need at least as many backslashes as double dots - thus, if you only allow relativePath
s with at least one more backslash, you should be safe.
To expand: use Path.Combine, then call GetFullPath on the result and check that that result starts with rootPath.
It won't protect you against hardlinks, but it should catch simple things like double-dots.
the above as code:
string Resolve(string fileName)
{
string root = FileRoot();
string ret = Path.GetFullPath(Path.Combine(root, fileName));
if (ret.StartsWith(root.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar)) return ret;
throw new ArgumentException("path resolved to out of accesable directroy");
}
You could just call Path.GetFullPath()
and check if it starts with your trusted rootPath
. If you tend to paranoia, check also that rootPath
is rooted.
public Boolean IsPathSafe(String rootPath, String relativePath)
{
return rootPath.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
Path.IsPathRooted(rootPath) &&
Patch.Combine(rootPath, relativePath).GetFullPath().StartsWith(rootPath);
}
For an explaination of the first test see Alex Martelli's comment on technophile's answer.