Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
doc: correct unsafe URL example in http docs
The previous documentation example for converting request.url to an URL
object was unsafe, as it could allow a server crash through malformed
URL inputs and potentially enable host header attacks. This commit
revises the example to use string concatenation, mitigating both the
crash and security risks by ensuring the host part of the URL remains
controlled and predictable.

Fixes: #52494
  • Loading branch information
thisalihassan committed Apr 15, 2024
commit bf1ce5900c74bdce192bc964cacface1fcce5e2d
8 changes: 4 additions & 4 deletions doc/api/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ const proxy = createServer((req, res) => {
});
proxy.on('connect', (req, clientSocket, head) => {
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const { port, hostname } = new URL(`http://${req.headers.host}${req.url}`);
Comment thread
thisalihassan marked this conversation as resolved.
Outdated
const serverSocket = connect(port || 80, hostname, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
Expand Down Expand Up @@ -543,7 +543,7 @@ const proxy = http.createServer((req, res) => {
});
proxy.on('connect', (req, clientSocket, head) => {
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const { port, hostname } = new URL(`http://${req.headers.host}${req.url}`);
Comment thread
thisalihassan marked this conversation as resolved.
Outdated
const serverSocket = net.connect(port || 80, hostname, () => {
clientSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
Expand Down Expand Up @@ -2886,15 +2886,15 @@ Accept: text/plain
To parse the URL into its parts:

```js
new URL(request.url, `http://${request.headers.host}`);
new URL(`http://${req.headers.host}${req.url}`);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not safer than the original, see #52494 (comment)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lpinca is correct. Relying on user headers for any part of the url parsing can lead to the malicious injection of a URL.

I believe the smartest idea would be to just include a note in the documentation that this setup is only an example and shouldn't be used in production for security reasons

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I reviewed without thoroughly analysis. I second @redyetidev idea.

@mlegenhausen mlegenhausen Apr 16, 2024 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to see a PR improving the docs. Maybe the best idea to fix the problem with the Host header is simply not to use it? Maybe something like this is better?

new URL(`http://localhost${request.url}`)
new URL(`http://${process.env.HOST ?? 'localhost'}${request.url}`)

I believe the smartest idea would be to just include a note in the documentation that this setup is only an example and shouldn't be used in production for security reasons

I actually read the nodeJS docs as a best practice 🙈 If it is not documented here who should come up with the best possible approach?

@avivkeller avivkeller Apr 16, 2024 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we were to go with your approach, we wouldn't need a note because it wouldn't present a security issue anymore :-).

If the team agrees with your suggestion, you should open a PR for it. With all the work you put into finding and fixing this issue, you should be the one to request it!

WDYT @lpinca and @ShogunPanda?

@mlegenhausen mlegenhausen Apr 16, 2024 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the team agrees with your suggestion, you should open a PR for it.

Sure can do. Waiting for an agree- or disagreement 🙈

With all the work you put into finding and fixing this issue, you should be the one to request it!

Team afford. Kudos to @astlouisf and @samhh

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@redyetidev I agree, I can close this one and @mlegenhausen can open a seperate PR to fix this issue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done #52555

```

When `request.url` is `'/status?name=ryan'` and `request.headers.host` is
`'localhost:3000'`:

```console
$ node
> new URL(request.url, `http://${request.headers.host}`)
> new URL(`http://${req.headers.host}${req.url}`)
URL {
href: 'http://localhost:3000/status?name=ryan',
origin: 'http://localhost:3000',
Expand Down