mirror of
https://github.com/withastro/astro.git
synced 2025-04-07 23:41:43 -05:00
Handle bad values in x-forwarded-host (#13428)
* Handle bad values in x-forwarded-host If a bad value is provide by this header, we simply ignore it and fallback to the host provided by the host header (if there is one). * Add changeset * Update packages/astro/src/core/app/node.ts Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev> --------- Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: Florian Lefebvre <contact@florian-lefebvre.dev>
This commit is contained in:
parent
65f7e09901
commit
9cac9f3142
3 changed files with 35 additions and 5 deletions
5
.changeset/true-moose-report.md
Normal file
5
.changeset/true-moose-report.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Prevent bad value in x-forwarded-host from crashing request
|
|
@ -75,19 +75,27 @@ export class NodeApp extends App {
|
|||
// We need to handle it here and parse the header correctly.
|
||||
// @example "https, http,http" => "http"
|
||||
const forwardedProtocol = getFirstForwardedValue(req.headers['x-forwarded-proto']);
|
||||
const protocol = forwardedProtocol ?? (isEncrypted ? 'https' : 'http');
|
||||
const providedProtocol = (isEncrypted ? 'https' : 'http');
|
||||
const protocol = forwardedProtocol ?? providedProtocol;
|
||||
|
||||
// @example "example.com,www2.example.com" => "example.com"
|
||||
const forwardedHostname = getFirstForwardedValue(req.headers['x-forwarded-host']);
|
||||
const hostname = forwardedHostname ?? req.headers.host ?? req.headers[':authority'];
|
||||
const providedHostname = req.headers.host ?? req.headers[':authority'];
|
||||
const hostname = forwardedHostname ?? providedHostname;
|
||||
|
||||
// @example "443,8080,80" => "443"
|
||||
const port = getFirstForwardedValue(req.headers['x-forwarded-port']);
|
||||
|
||||
const portInHostname = typeof hostname === 'string' && /:\d+$/.test(hostname);
|
||||
const hostnamePort = portInHostname ? hostname : `${hostname}${port ? `:${port}` : ''}`;
|
||||
let url: URL;
|
||||
try {
|
||||
const hostnamePort = getHostnamePort(hostname, port);
|
||||
url = new URL(`${protocol}://${hostnamePort}${req.url}`);
|
||||
} catch {
|
||||
// Fallback to the provided hostname and port
|
||||
const hostnamePort = getHostnamePort(providedHostname, port);
|
||||
url = new URL(`${providedProtocol}://${hostnamePort}`);
|
||||
}
|
||||
|
||||
const url = `${protocol}://${hostnamePort}${req.url}`;
|
||||
const options: RequestInit = {
|
||||
method: req.method || 'GET',
|
||||
headers: makeRequestHeaders(req),
|
||||
|
@ -161,6 +169,12 @@ export class NodeApp extends App {
|
|||
}
|
||||
}
|
||||
|
||||
function getHostnamePort(hostname: string | string[] | undefined, port?: string): string {
|
||||
const portInHostname = typeof hostname === 'string' && /:\d+$/.test(hostname);
|
||||
const hostnamePort = portInHostname ? hostname : `${hostname}${port ? `:${port}` : ''}`;
|
||||
return hostnamePort;
|
||||
}
|
||||
|
||||
function makeRequestHeaders(req: NodeRequest): Headers {
|
||||
const headers = new Headers();
|
||||
for (const [name, value] of Object.entries(req.headers)) {
|
||||
|
|
|
@ -86,6 +86,17 @@ describe('NodeApp', () => {
|
|||
});
|
||||
assert.equal(result.url, 'https://example.com/');
|
||||
});
|
||||
|
||||
it('bad values are ignored and fallback to host header', () => {
|
||||
const result = NodeApp.createRequest({
|
||||
...mockNodeRequest,
|
||||
headers: {
|
||||
host: 'example.com',
|
||||
'x-forwarded-host': ':123'
|
||||
},
|
||||
});
|
||||
assert.equal(result.url, 'https://example.com/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('x-forwarded-proto', () => {
|
||||
|
|
Loading…
Add table
Reference in a new issue