-
Notifications
You must be signed in to change notification settings - Fork 5k
[API Proposal]: Add a [System.IO.Path]
method to ensure that a relative path stays inside a directory
#89785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Tagging subscribers to this area: @dotnet/area-system-io Issue DetailsBackground and motivationSee golang/go#56219 for a similar feature request for Go. It is common for programs to accept filenames from untrusted sources. For example, an archive extractor might create files based on names in the archive, or a web server may serve the content of local files identified by a URL path. In both cases, the untrusted path is a relative path that should never leave a known directory specified in the program, e.g. if serving files from Currently, user has to do this validation by hand, either by trying to parse the relative path directly (which is non-trivial and ripe with edge cases), or doing something like var resolvedPath = Path.GetFullPath(Path.Combine(basePath, untrustedPath));
if (resolvedPath.StartsWith(basePath + Path.DirectorySeparatorChar)) { ... } , of which I've also seen multiple incorrect variants on StackOverflow and similar sites (typically forgetting to add the directory separator to API ProposalAdd a new method to API Usagevar untrustedPath = readClientRequest();
if (!Path.IsPathLocal(untrustedPath)) {
sendError("can't touch that");
return;
}
// use `untrustedPath` Alternative Designs
|
Author: | MatejKafka |
---|---|
Assignees: | - |
Labels: |
|
Milestone: | - |
Before you try working with startswith, take a look at https://learn.microsoft.com/en-us/dotnet/api/system.io.path.getrelativepath?view=net-7.0#system-io-path-getrelativepath(system-string-system-string) and then check if the return of that method contains That method also takes care of |
From a usefulness standpoint, something that only checks if a path is a subdirectory of working directory seems overly restrictive. And potentially its own security hole, because the working directory might not be what you expect, anyways (as opposed to the source directory of the application). I personally would prefer some sort of |
I'm not sure that any examination of strings can provide a bulletproof guarantee, given variations in OS and file system behaviors, hard links, and so forth. This is something code access security (CAS) tried to do. The only sure way is likely to have the OS tell you, somehow. |
The proposed API is not dependent on the current working directory. If the @danmoseley I'm also not sure about that, but as long as symlinks are not involved, I haven't found any path where interaction with the filesystem is necessary to determine whether it's safe. If such paths exist, it might be necessary to use a different implementation for each platform (which is consistent with what other methods in |
This is a dupe of #87581 I think. I gave some commentary there on design of such an API: #87581 (comment) |
Background and motivation
See golang/go#56219 for a similar feature request for Go.
It is common for programs to accept filenames from untrusted sources. For example, an archive extractor might create files based on names in the archive, or a web server may serve the content of local files identified by a URL path. In both cases, the untrusted path is a relative path that should never leave a known directory specified in the program, e.g. if serving files from
D:\webserver
, paths like../dir
must not allow the user to readD:\dir
.Currently, user has to do this validation by hand, either by trying to parse the relative path directly (which is non-trivial and ripe with edge cases), or doing something like
, of which I've also seen multiple incorrect variants on StackOverflow and similar sites (typically forgetting to add the directory separator to
basePath
). For either of these options, I'm not convinced that I can write a correct implementation without a lot of fuzzing.API Proposal
Add a new method to
System.IO.Path
,bool IsPathLocal(string relativePath)
, which returns true ifrelativePath
does not leave the current directory. The method should not be dependent on any particular directory, operating only on the string path, without referencing the filesystem.API Usage
Alternative Designs
..
handlingI see two possibilities of how paths containing
..
could be handled:..
as a segment. This is more restrictive, but I'd assume that in practice, it would work as well as the first variant for common scenarios while being much simpler to implement.Retrieving the full path
Alternatively, the API could be implemented as a method
string? JoinLocal(string basePath, string relativePath)
(not sure about the name), which also receives the base directory and returns astring?
which either contains the resolved absolute path, or is null ifrelativePath
is not local. This might be more performant, since the API user will typically want to eventually resolve the path, but combines validation and resolution into a single API, which might be less flexible in cases where the API user wants to do the validation upfront, but only resolve the path later in the program.Risks
No response
The text was updated successfully, but these errors were encountered: