It seems that express default behaviour is to normalize URLs containing up directory (/../)
For the code below, if I request a URL like this
http://localhost:8080/foo/../../bar
the request gets redirected to
http://localhost:8080/bar
I couldn't find any detailed documentation on this behavior.
my questions are:
- is it a guaranteed behavior
- in case I am not serving from a file system is there a way to preserve the original URL "path" in case i am using other processing?
by
const express = require("express")
const app=express()
app.get("/*", (req,res) => {
console.log("url:",req.url);
console.log("path:",req.path);
res.send('echo for url=' req.url '; path=' req.path')
}
const port=8080;
app.listen(port,() =>{
console.log(`listening on port ${port}`);
});
CodePudding user response:
The request is not redirected, but rather the client rebuilds the URL before making the request
>curl -v http://localhost:8080/foo/../../bar
* Rebuilt URL to: http://localhost:8080/bar
Therefore the server never sees the "original URL path".
This URL rebuilding is part of the resolution process. See also https://url.spec.whatwg.org/#concept-basic-url-parser.
A malicious client (e.g., a telnet client) could, however, send an HTTP request with "unresolved" URL. The following middleware demonstrates how to rebuild the URL on the server:
function(req, res) {
res.json({path: req.path,
rebuilt_path: new URL("s://" req.path).pathname});
}
The malicious request
GET /foo/../../bar HTTP/1.1
Host: localhost:8080
then returns
{"path": "/foo/../../bar", "rebuilt_path": "/bar"}
