By far the best way to defeat path traversal flaws is to avoid passing user-supplied data to any filesystem API. In many situations, including the original example File.ashx?filename=file.jpg, it is useless for an application to do this.
Files that are not subject to any access control can easily be placed within the web root and accessed via a direct URL. If that is impossible, the application can maintain a hard-coded list of image files that may be rendered by the page. It can use a different identifier to define which file is needed, such as an index number. Any request including an invalid identifier can be refused, and there is no attack surface for users to manipulate the path of files presented by the page.
In some cases, as with the work flow functionality that enables file uploading and downloading, it’s good to enable users to specify files by name. Developers may decide that the easiest way to perform this is by passing the user-supplied filename to filesystem APIs. In this condition, the application should take a defense-in-depth approach to place some obstacles in the way of a path traversal attack.
The application can reduce the effect of most path traversal flaws by using a “chrooted” environment to access the directory including the files to be accessed. In this condition, the chrooted directory is considered as if it is the filesystem root, which means that any redundant traversal series that try to step up above it is ignored.
Chrooted filesystems are supported on most UNIX-based platforms. The same impact can be delivered on Windows platforms by mounting the appropriate start directory as a new logical drive and using the associated drive letter to access its contents.
Whenever a request is received that includes path traversal series, that means there is a possible malicious purpose on the user’s side. The application should log the request as a possible security breach, eliminate the user’s session, and, if possible, suspend the user’s account and generate a warning to the administrator.