tags:

views:

195

answers:

4

I have an asp.net mvc app with a route that allows users to request files that are stored outside of the web application directory.

I'll simplify the scenario by just telling you that it's going to ultimately confine them to a safe directory to which they have full access.

For example:

If the user (whose ID is 100) requests:

http://mysite.com/Read/Image/Cool.png

then my app is going to append "Cool.png" to "C:\ImageRepository\Users\100\" and write those bytes to the response. The worker process has access to this path, but the anonymous user does not. I already have this working.

But will some malicious user be able to request something like:

http://mysite.com/Read/Image/..\101\Cool.png

and have it resolve to

"C:\ImageRepository\Customers\101\Cool.png"

(some other user's image?!)

Or something like that? Is there a way to make sure the path is clean, such that the user is constrained to their own directory?

+3  A: 

How about

var fileName = System.IO.Path.GetFileName(userFileName);
var targetPath = System.IO.Path.Combine(userDirectory, fileName);

That should ensure you get a simple filename only.

Tor Haugen
I'm going to read about these methods right away and play around with them in Linqpad. I have a hunch this is the right direction.
Chris
This throws exceptions whenever I mess with the input, so I think this is the way to go.
Chris
A: 

Perhaps you should verify that the path starts with the user's directory path?

e.g. "C:\ImageRepository\Customers\100\"

You should also normalize the paths to uppercase letters when comparing them.

Zach Johnson
So how about C:\ImageRepository\Customers\100\..\101\secretstuff.png?
DrJokepu
He should first resolve the path to its most simple form, and then verify that the path is prefixed by the correct path.
Zach Johnson
Ok, so maybe a combination of Tor's answer and your .StartsWith() suggestion?
Chris
I know it's nitpicking, but "resolving to the most simple form" is not straightforward at all, given that NTFS supports junctions (hard links). All I'm saying I guess that this problem is a lot more complicated than it looks like at first glance.
DrJokepu
A: 

The safest way, if it is an option (you are using windows auth), is to make it a non-issue by using Active Directory rights on the folders so it doesn't matter if the user attempts to access a directory that is not valid.

Absent that, store the files so that the path is abstracted from the user. That is, use whatever name the user provides as a lookup in a table that has the REAL path to the file.

Cannolocalization protection is tricky business and it is dangerous to try and outthink a potential attacker.

JohnFx
Unfortunately this app is destined for the internets.
Chris
Which means what, exactly?
JohnFx
A: 

Using the Request.MapPath overload is one way to check this:

try
{
  string mappedPath = Request.MapPath( inputPath.Text,                                  Request.ApplicationPath, false);
}
catch (HttpException)
{
  // do exception handling
}

Also you could explode the string and delimit it by slashes, and check the username match also.

Jeremy Morgan