Skip to content

Commit 1fa6823

Browse files
committed
set address header explicitly
1 parent bbf862c commit 1fa6823

File tree

6 files changed

+54
-84
lines changed

6 files changed

+54
-84
lines changed

packages/adapter-node/README.md

+26-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default {
2626
host: 'HOST_HEADER'
2727
}
2828
},
29-
trustProxy: false
29+
xForwardedForIndex: -1
3030
})
3131
}
3232
};
@@ -64,6 +64,14 @@ PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host node build
6464

6565
> [`x-forwarded-proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) and [`x-forwarded-host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) are de facto standard headers that forward the original protocol and host if you're using a reverse proxy (think load balancers and CDNs). You should only set these variables if you trust the reverse proxy.
6666
67+
The [RequestEvent](https://kit.svelte.dev/docs/types#additional-types-requestevent) object passed to hooks and endpoints includes an `event.clientAddress` property representing the client's IP address. By default this is the connecting `remoteAddress`. If your server is behind one or more proxies (such as a load balancer), this value will contain the innermost proxy's IP address rather than the client's, so we need to specify an `ADDRESS_HEADER` to read the address from:
68+
69+
```
70+
ADDRESS_HEADER=True-Client-IP node build
71+
```
72+
73+
> Headers can easily be spoofed. As with `PROTOCOL_HEADER` and `HOST_HEADER`, you should [know what you're doing](https://adam-p.ca/blog/2022/03/x-forwarded-for/) before setting these.
74+
6775
All of these environment variables can be changed, if necessary, using the `env` option:
6876

6977
```js
@@ -72,6 +80,7 @@ env: {
7280
port: 'MY_PORT_VARIABLE',
7381
origin: 'MY_ORIGINURL',
7482
headers: {
83+
address: 'MY_ADDRESS_HEADER',
7584
protocol: 'MY_PROTOCOL_HEADER',
7685
host: 'MY_HOST_HEADER'
7786
}
@@ -85,9 +94,23 @@ MY_ORIGINURL=https://my.site \
8594
node build
8695
```
8796

88-
### trustProxy
97+
### xForwardedForIndex
98+
99+
If the `ADDRESS_HEADER` is `X-Forwarded-For`, the header value will contain a comma-separated list of IP addresses. For example, if there are three proxies between your server and the client, proxy 3 will forward the addresses of the client and the first two proxies:
100+
101+
```
102+
<client address>, <proxy 1 address>, <proxy 2 address>
103+
```
104+
105+
To get the client address we could use `xForwardedFor: 0` or `xForwardedFor: -3`, which counts back from the number of addresses.
106+
107+
**X-Forwarded-For is [trivial to spoof](https://adam-p.ca/blog/2022/03/x-forwarded-for/), howevever**:
108+
109+
```
110+
<spoofed address>, <client address>, <proxy 1 address>, <proxy 2 address>
111+
```
89112

90-
In order for `event.clientAddress` to show the client's IP address, `adapter-node` must read it from one of several possible request headers. Since these headers can be spoofed, it will only do this if `trustProxy` is `true`.
113+
For that reason you should always use a negative number (depending on the number of proxies) if you need to trust `event.clientAddress`. In the above example, `0` would yield the spoofed address while `-3` would continue to work.
91114

92115
## Custom server
93116

packages/adapter-node/index.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ interface AdapterOptions {
1515
port?: string;
1616
origin?: string;
1717
headers?: {
18+
address?: string;
1819
protocol?: string;
1920
host?: string;
2021
};
2122
};
22-
trustProxy?: boolean;
23+
xForwardedForIndex?: number;
2324
}
2425

2526
declare function plugin(options?: AdapterOptions): Adapter;

packages/adapter-node/index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ export default function ({
1919
port: port_env = 'PORT',
2020
origin: origin_env = 'ORIGIN',
2121
headers: {
22+
address: address_header_env = 'ADDRESS_HEADER',
2223
protocol: protocol_header_env = 'PROTOCOL_HEADER',
2324
host: host_header_env = 'HOST_HEADER'
2425
} = {}
2526
} = {},
26-
trustProxy = false
27+
xForwardedForIndex = -1
2728
} = {}) {
2829
return {
2930
name: '@sveltejs/adapter-node',
@@ -54,7 +55,8 @@ export default function ({
5455
ORIGIN: origin_env ? `process.env[${JSON.stringify(origin_env)}]` : 'undefined',
5556
PROTOCOL_HEADER: JSON.stringify(protocol_header_env),
5657
HOST_HEADER: JSON.stringify(host_header_env),
57-
TRUST_PROXY: JSON.stringify(trustProxy)
58+
ADDRESS_HEADER: JSON.stringify(address_header_env),
59+
X_FORWARDED_FOR_INDEX: JSON.stringify(xForwardedForIndex)
5860
}
5961
});
6062

packages/adapter-node/src/get-client-address.js

-72
This file was deleted.

packages/adapter-node/src/handler.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import type { Handle } from '@sveltejs/kit';
22

33
declare global {
44
const ORIGIN: string;
5+
const ADDRESS_HEADER: string;
56
const HOST_HEADER: string;
67
const PROTOCOL_HEADER: string;
7-
const TRUST_PROXY: boolean;
8+
const X_FORWARDED_FOR_INDEX: number;
89
}
910

1011
export const handler: Handle;

packages/adapter-node/src/handler.js

+20-5
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { fileURLToPath } from 'url';
66
import { getRequest, setResponse } from '@sveltejs/kit/node';
77
import { Server } from 'SERVER';
88
import { manifest } from 'MANIFEST';
9-
import { get_client_address } from './get-client-address';
109

11-
/* global ORIGIN, PROTOCOL_HEADER, HOST_HEADER, TRUST_PROXY */
10+
/* global ORIGIN, ADDRESS_HEADER, PROTOCOL_HEADER, HOST_HEADER */
1211

1312
const server = new Server(manifest);
1413
const origin = ORIGIN;
14+
15+
const address_header = ADDRESS_HEADER && (process.env[ADDRESS_HEADER] || '').toLowerCase();
1516
const protocol_header = PROTOCOL_HEADER && process.env[PROTOCOL_HEADER];
1617
const host_header = (HOST_HEADER && process.env[HOST_HEADER]) || 'host';
1718

@@ -50,11 +51,25 @@ const ssr = async (req, res) => {
5051
res,
5152
await server.respond(request, {
5253
getClientAddress: () => {
53-
if (TRUST_PROXY) {
54-
return get_client_address(req);
54+
if (address_header) {
55+
const value = /** @type {string} */ (req.headers[address_header]) || '';
56+
57+
if (address_header === 'x-forwarded-for') {
58+
const addresses = value.split(',');
59+
return addresses[(addresses.length + X_FORWARDED_FOR_INDEX) % addresses.length].trim();
60+
}
61+
62+
return value;
5563
}
5664

57-
throw new Error('You must enable the adapter-node trustProxy option to read clientAddress');
65+
return (
66+
req.connection?.remoteAddress ||
67+
// @ts-expect-error
68+
req.connection?.socket?.remoteAddress ||
69+
req.socket?.remoteAddress ||
70+
// @ts-expect-error
71+
req.info?.remoteAddress
72+
);
5873
}
5974
})
6075
);

0 commit comments

Comments
 (0)