Skip to content

Commit

Permalink
feat: support config.maxIpsCount (#4014)
Browse files Browse the repository at this point in the history
  • Loading branch information
dead-horse committed Oct 28, 2019
1 parent 380e7d6 commit b3479e8
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 12 deletions.
10 changes: 7 additions & 3 deletions app/extend/request.js
Expand Up @@ -92,10 +92,14 @@ module.exports = {
const val = getFromHeaders(this, this.app.config.ipHeaders) || '';
this[IPS] = val ? val.split(/\s*,\s*/) : [];

if (this.app.config.maxProxyCount > 0) {
// if maxProxyCount present, only keep `maxProxyCount + 1` ips
let maxIpsCount = this.app.config.maxIpsCount;
// Compatible with maxProxyCount logic (previous logic is wrong, only for compatibility with legacy logic)
if (!maxIpsCount && this.app.config.maxProxyCount) maxIpsCount = this.app.config.maxProxyCount + 1;

if (maxIpsCount > 0) {
// if maxIpsCount present, only keep `maxIpsCount` ips
// [ illegalIp, clientRealIp, proxyIp1, proxyIp2 ...]
this[IPS] = this[IPS].slice(-(this.app.config.maxProxyCount + 1));
this[IPS] = this[IPS].slice(-maxIpsCount);
}
return this[IPS];
},
Expand Down
16 changes: 13 additions & 3 deletions config/config.default.js
Expand Up @@ -48,12 +48,22 @@ module.exports = appInfo => {
proxy: false,

/**
* How many proxies the application deployed behind
* framework use this to get the clients' real ips
* `0` means not limited, for most common usage, it should be `1`
*
* max ips read from proxy ip header, default to 0 (means infinity)
* to prevent users from forging client ip addresses via x-forwarded-for
* @see https://github.com/koajs/koa/blob/master/docs/api/request.md#requestips
* @member {Integer} Config#maxIpsCount
* @default
* @since 2.25.0
*/
maxIpsCount: 0,

/**
* please use maxIpsCount instead
* @member {Integer} Config#maxProxyCount
* @default
* @since 2.21.0
* @deprecated
*/
maxProxyCount: 0,

Expand Down
8 changes: 5 additions & 3 deletions docs/source/en/tutorials/proxy.md
Expand Up @@ -27,7 +27,7 @@ When the proxy configuration is enabled, the app parses the [X-Forwarded-For](ht
exports.ipHeaders = 'X-Real-Ip, X-Forwarded-For';
```

### `config.maxProxyCount`
### `config.maxIpsCount`

The general format of the `X-Forwarded-For` field is:

Expand All @@ -41,14 +41,16 @@ We can use the first IP address as the real IP adderess of the request, but if a
X-Forwarded-For: fake, client, proxy1, proxy2
```

In order to avoid this problem, we can configure the number of reverse proxies through `config.maxProxyCount`, so the fake IP address passed by the user will be ignored. For example, if we deploy the application behind a unified access layer (such as Alibaba Cloud SLB, Amazon ELB), we can configure this configuration to `1` so that users cannot forge IP addresses through the `X-Forwarded-For` request header.
In order to avoid this problem, we can configure the number of reverse proxies through `config.maxIpsCount`, so the fake IP address passed by the user will be ignored. For example, if we deploy the application behind a unified access layer (such as Alibaba Cloud SLB, Amazon ELB), we can configure this configuration to `1` so that users cannot forge IP addresses through the `X-Forwarded-For` request header.

```js
// config/config.default.js

exports.maxProxyCount = 1;
exports.maxIpsCount = 1;
```

This configuration item has the same effect as `options.maxIpsCount` provided by [koa](https://github.com/koajs/koa/blob/master/docs/api/request.md#requestips).

### `config.protocolHeaders`

When the proxy configuration is enabled, the application will parse the [X-Forwarded-Proto] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) request header to get the client's Real access protocol. If your reverse proxy passes this information through other request headers, it can be configured via `config.protocolHeaders`, which supports multiple headers (comma separated).
Expand Down
8 changes: 5 additions & 3 deletions docs/source/zh-cn/tutorials/proxy.md
Expand Up @@ -27,7 +27,7 @@ exports.proxy = true;
exports.ipHeaders = 'X-Real-Ip, X-Forwarded-For';
```

### `config.maxProxyCount`
### `config.maxIpsCount`

`X-Forwarded-For` 等传递 IP 的头,通用的格式是:

Expand All @@ -41,14 +41,16 @@ X-Forwarded-For: client, proxy1, proxy2
X-Forwarded-For: fake, client, proxy1, proxy2
```

为了避免此问题,我们可以通过 `config.maxProxyCount` 来配置前置的反向代理数量,这样在获取请求真实 IP 地址时,就会忽略掉用户多传递的伪造 IP 地址了。例如我们将应用部署在一个统一的接入层之后(例如阿里云 SLB),我们可以将此参数配置为 `1`,这样用户就无法通过 `X-Forwarded-For` 请求头来伪造 IP 地址了。
为了避免此问题,我们可以通过 `config.maxIpsCount` 来配置前置的反向代理数量,这样在获取请求真实 IP 地址时,就会忽略掉用户多传递的伪造 IP 地址了。例如我们将应用部署在一个统一的接入层之后(例如阿里云 SLB),我们可以将此参数配置为 `1`,这样用户就无法通过 `X-Forwarded-For` 请求头来伪造 IP 地址了。

```js
// config/config.default.js

exports.maxProxyCount = 1;
exports.maxIpsCount = 1;
```

此配置项与 [koa](https://github.com/koajs/koa/blob/master/docs/api/request.md#requestips) 提供的 `options.maxIpsCount` 作用一致。

### `config.protocolHeaders`

开启 proxy 配置后,应用会解析 [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) 请求头来获取客户端的真实访问协议。如果你的前置代理通过其他的请求头来传递该信息,可以通过 `config.protocolHeaders` 来配置,这个配置项支持配置多个头(逗号分开)。
Expand Down
6 changes: 6 additions & 0 deletions test/app/extend/request.test.js
Expand Up @@ -98,6 +98,12 @@ describe('test/app/extend/request.test.js', () => {
assert.deepEqual(req.ips, [ '127.0.0.2', '127.0.0.3' ]);
});

it('should used work with maxIpsCount', () => {
mm(req.header, 'x-forwarded-for', '127.0.0.1,127.0.0.2,127.0.0.3');
mm(app.config, 'maxIpsCount', 1);
assert.deepEqual(req.ips, [ '127.0.0.3' ]);
});

it('should used x-real-ip', () => {
mm(app.config, 'ipHeaders', 'X-Forwarded-For, X-Real-IP');
mm(req.header, 'x-forwarded-for', '');
Expand Down

0 comments on commit b3479e8

Please sign in to comment.