views:

48

answers:

4

I know the solid security recommendation of avoiding accepting user input that you then use to choose a path to read/write a file. However, assuming you have a base directory you want to keep within (such as the root of an ftp folder), how do you best ensure that a given user input keeps us within that folder?

For instance,

Path.Combine(_myRootFolder, _myUserInput)

could still take us outside of _myRootFolder. And this could also be dodgy

newPath = Path.Combine(_myRootFolder, _myUserInput) if (newPath.StartsWith(_myRootFolder)) ...

given something like "/back/to/myrootfolder/../../and/out/again" from the user. What are the strategies for this? Am I missing a blindingly obvious .NET method I can use?

Thanks!

A: 

You can parse input string and cut ../ with regex.

x2
What I'm hoping to avoid is relying on my own knowledge of path shortcuts though. Is "../" definitely the only way of moving up a path? Can you do URL type tricks of encoding in weird unicode characters for example.... I'd rather do a check after the file path has been fully unescaped, if that's possible?
James Crowley
A: 

Well, in your example of an FTP server, you should set the users home-directory, and permissions appropriately, such that they can't navigate out of the folder. Any reason you can't do that?

Noon Silk
+1  A: 

Within ASP.NET applications you can use Server.MapPath(filename) which will throw an exception if the path generated goes outside of your application root.

If all you want is a safe file name and you just want all files in there it becomes simpler;

    FileInfo file = new FileInfo(
        Server.MapPath(
            Path.Combine(@"c:\example\mydir", filename)));

If you're outside of ASP.NET like you indicate then you could use Path.GetFullPath.

string potentalPath = Path.Combine(@"c:\myroot\", fileName);
if (Path.GetFullPath(potentialPath) ! = potentialPath)
    // Potential path transversal

Or you call Path.GetFullPath and then check the start of it matches the directory you want locked to.

blowdart
Yeah, that's the sort of functionality I want... except I'm unfortunately in a Windows Service that is batch uploading a bunch of files from one place to another.
James Crowley
Added another approach then
blowdart
Cool - thanks - GetFullPath looks like the way to go :)
James Crowley
+1  A: 

I believe Path.FullPath will do what you need (I didn't test this though):

string newPath = Path.Combine(_myRootFolder, _myUserInput);
string newPath = Path.FullPath(newPath);
if (newPath.StartsWith(_myRootFolder)) ...
Joe