Skip to content
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

Attempt to fix #356 #357

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

schuelermine
Copy link

This is an attempt to fix #356 in case any implementation from upstream (deno std library) is not to be expected

Adds import of sep from std/path
Attempt to fix oakserver#356
@kitsonk
Copy link
Collaborator

kitsonk commented Jul 5, 2021

We should try to find a way to test this, as I am not 100% clear under what conditions it fails. A specific example in the issue and a test would really help in understanding if the fix is correct.

@schuelermine
Copy link
Author

@kitsonk What’s happening is that the Deno standard library’s path.parse function spits out an object that separates out the root of the path, which is the initial slash on Linux/macOS, and the drive letter on Windows. send then strips out this segment. However, it doesn’t strip out multiple slashes, because parse only recognizes the first slash as the root. This stripping out is done because resolvePath (from oak) expects a relative path without an initial slash as its second argument, and throws a BadRequestError with message “Malicious Path”, because it thinks the user is trying to access the root directory.

Example REPL session (click to expand)
$ deno
Deno 1.11.2
exit using ctrl+d or close()
> const Path = await import("https://deno.land/std/path/mod.ts");
undefined
> const Send = await import("https://deno.land/x/oak/send.ts");
undefined
> const Util = await import("https://deno.land/x/oak/util.ts");
undefined
> Path.parse("/home");
{ root: "/", dir: "/", base: "home", ext: "", name: "home" }
> Path.parse("home");
{ root: "", dir: "", base: "home", ext: "", name: "home" }
> Path.parse("//home");
{ root: "/", dir: "/", base: "home", ext: "", name: "home" }
> Util.resolvePath("/", ".");
"/"
> Util.resolvePath("/", "home");
"/home"
> Util.resolvePath("/", "/home");
Uncaught BadRequestError: Malicious Path
    at createHttpError (https://deno.land/x/[email protected]/httpError.ts:130:10)
    at Module.resolvePath (https://deno.land/x/[email protected]/util.ts:313:11)
    at <anonymous>:2:6

On Linux, // is a valid alias for /, even though / is not a child of /. A webserver essentially imitates a changed root, evidenced by the use of / to refer to the root of the webserver’s virtual filesystem, and should therefore accept //. What’s more, most prominent websites seem to recognize // as simply pointing to the root.

This PR addresses this by stripping out any remaining initial slashes via a regex match. This is safe, since Windows doesn’t allow slashes in paths. An alternative solution would be to prepend ./ to the path before passing it into resolvePath, since resolvePath tolerates double slashes inside the path.

I believe that the fact that // is not reported as the root by parse may be an upstream bug, which is why I noted this in the body of the PR.

@schuelermine
Copy link
Author

This is a test comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

send fails when // is given as path
2 participants