mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 21:58:48 +02:00
url: runtime-deprecate url.parse() with invalid ports
These URLs throw with WHATWG URL. They are permitted with url.parse() but that allows potential host spoofing by sending a domain name as the port. PR-URL: https://github.com/nodejs/node/pull/45526 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
2589fb1f6b
commit
3bed5f11e0
3 changed files with 45 additions and 3 deletions
|
@ -3302,13 +3302,17 @@ issued for `url.parse()` vulnerabilities.
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
changes:
|
changes:
|
||||||
|
- version:
|
||||||
|
- REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/45526
|
||||||
|
description: Runtime deprecation.
|
||||||
- version:
|
- version:
|
||||||
- v19.2.0
|
- v19.2.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/45576
|
pr-url: https://github.com/nodejs/node/pull/45576
|
||||||
description: Documentation-only deprecation.
|
description: Documentation-only deprecation.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
Type: Documentation-only
|
Type: Runtime
|
||||||
|
|
||||||
[`url.parse()`][] accepts URLs with ports that are not numbers. This behavior
|
[`url.parse()`][] accepts URLs with ports that are not numbers. This behavior
|
||||||
might result in host name spoofing with unexpected input. These URLs will throw
|
might result in host name spoofing with unexpected input. These URLs will throw
|
||||||
|
|
13
lib/url.js
13
lib/url.js
|
@ -387,7 +387,7 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
|
||||||
|
|
||||||
// validate a little.
|
// validate a little.
|
||||||
if (!ipv6Hostname) {
|
if (!ipv6Hostname) {
|
||||||
rest = getHostname(this, rest, hostname);
|
rest = getHostname(this, rest, hostname, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hostname.length > hostnameMaxLen) {
|
if (this.hostname.length > hostnameMaxLen) {
|
||||||
|
@ -506,7 +506,8 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getHostname(self, rest, hostname) {
|
let warnInvalidPort = true;
|
||||||
|
function getHostname(self, rest, hostname, url) {
|
||||||
for (let i = 0; i < hostname.length; ++i) {
|
for (let i = 0; i < hostname.length; ++i) {
|
||||||
const code = hostname.charCodeAt(i);
|
const code = hostname.charCodeAt(i);
|
||||||
const isValid = (code !== CHAR_FORWARD_SLASH &&
|
const isValid = (code !== CHAR_FORWARD_SLASH &&
|
||||||
|
@ -516,6 +517,14 @@ function getHostname(self, rest, hostname) {
|
||||||
code !== CHAR_COLON);
|
code !== CHAR_COLON);
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
|
// If leftover starts with :, then it represents an invalid port.
|
||||||
|
// But url.parse() is lenient about it for now.
|
||||||
|
// Issue a warning and continue.
|
||||||
|
if (warnInvalidPort && code === CHAR_COLON) {
|
||||||
|
const detail = `The URL ${url} is invalid. Future versions of Node.js will throw an error.`;
|
||||||
|
process.emitWarning(detail, 'DeprecationWarning', 'DEP0170');
|
||||||
|
warnInvalidPort = false;
|
||||||
|
}
|
||||||
self.hostname = hostname.slice(0, i);
|
self.hostname = hostname.slice(0, i);
|
||||||
return `/${hostname.slice(i)}${rest}`;
|
return `/${hostname.slice(i)}${rest}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const childProcess = require('child_process');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
|
|
||||||
// https://github.com/joyent/node/issues/568
|
// https://github.com/joyent/node/issues/568
|
||||||
|
@ -74,3 +75,31 @@ if (common.hasIntl) {
|
||||||
(e) => e.code === 'ERR_INVALID_URL',
|
(e) => e.code === 'ERR_INVALID_URL',
|
||||||
'parsing http://\u00AD/bad.com/');
|
'parsing http://\u00AD/bad.com/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const badURLs = [
|
||||||
|
'https://evil.com:.example.com',
|
||||||
|
'git+ssh://git@github.com:npm/npm',
|
||||||
|
];
|
||||||
|
badURLs.forEach((badURL) => {
|
||||||
|
childProcess.exec(`${process.execPath} -e "url.parse('${badURL}')"`,
|
||||||
|
common.mustCall((err, stdout, stderr) => {
|
||||||
|
assert.strictEqual(err, null);
|
||||||
|
assert.strictEqual(stdout, '');
|
||||||
|
assert.match(stderr, /\[DEP0170\] DeprecationWarning:/);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Warning should only happen once per process.
|
||||||
|
const expectedWarning = [
|
||||||
|
`The URL ${badURLs[0]} is invalid. Future versions of Node.js will throw an error.`,
|
||||||
|
'DEP0170',
|
||||||
|
];
|
||||||
|
common.expectWarning({
|
||||||
|
DeprecationWarning: expectedWarning,
|
||||||
|
});
|
||||||
|
badURLs.forEach((badURL) => {
|
||||||
|
url.parse(badURL);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue