Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add how to config egg behind a proxy #3614

Merged
merged 1 commit into from
Apr 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/_data/guide_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Tutorials:
Socket.IO: /tutorials/socketio.html
Assets: /tutorials/assets.html
TypeScript: /tutorials/typescript.html
Proxy: /tutorials/proxy.html
Advanced:
Loader: /advanced/loader.html
Plugin Development: /advanced/plugin.html
Expand Down
72 changes: 72 additions & 0 deletions docs/source/en/tutorials/proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
title: Behind a Proxy
---

Generally, our services will not directly accept external requests, but will deploy the services behind the access layer, thus achieving load balancing of multiple machines and smooth distribution of services to ensure high availability.

In this scenario, we can't directly get the connection to the real user request, so we can't confirm the user's real IP, request protocol, or even the requested host. To solve this problem, the framework provides a set of configuration items by default for developers to configure to enable the application layer to obtain real user request information based on the agreement(de facto) with the access layer.

## Enable Proxy Mode

The proxy mode can be enabled by `config.proxy = true`:

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

exports.proxy = true;
```

Note that after this mode is enabled, the application defaults to being behind the reverse proxy. It will support the request header of the resolved protocol to obtain the real IP, protocol and host of the client. If your service is not deployed behind a reverse proxy, do not enable this configuration in case a malicious user falsifies information such as requesting IP.

### `config.ipHeaders`

When the proxy configuration is enabled, the app parses the [X-Forwarded-For](https://en.wikipedia.org/wiki/X-Forwarded-For) request header to get the real IP of the client. If your reverse proxy passes this information through other request headers, it can be configured via `config.ipHeaders`, which supports multiple headers (comma separated).

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

exports.ipHeaders = 'X-Real-Ip, X-Forwarded-For';
```

### `config.maxProxyCount`

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

```
X-Forwarded-For: client, proxy1, proxy2
```

We can use the first IP address as the real IP adderess of the request, but if a malicious user passes the `X-Forwarded-For` header in the request to spoof it after some reverse proxy, it will cause `X-Forwarded-For` to take The value obtained is inaccurate and can be used to spoof the request IP address, breaking some IP restrictions of the application layer.

```
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.

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

exports.maxProxyCount = 1;
```

### `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).

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

exports.protocolHeaders = 'X-Real-Proto, X-Forwarded-Proto';
```

### `config.hostHeaders`

When the proxy configuration is enabled, the application still reads `host` directly to get the requested domain name. Most of the reverse proxy does not modify this value. But maybe some reverse proxy will pass the client's real access via [X-Forwarded-Host] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) The domain name can be configured via `config.hostHeaders`, which supports multiple headers (comma separated).

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

exports.hostHeaders = 'X-Forwarded-Host';
```


1 change: 1 addition & 0 deletions docs/source/languages/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ guide_toc:
Resource: Resource
Assets: Assets
TypeScript: TypeScript
Proxy: Behind a Proxy
1 change: 1 addition & 0 deletions docs/source/languages/zh-cn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ guide_toc:
Resource: 资源
Assets: 静态资源
TypeScript: TypeScript
Proxy: 前置代理模式
72 changes: 72 additions & 0 deletions docs/source/zh-cn/tutorials/proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
title: 前置代理模式
Copy link
Member

Choose a reason for hiding this comment

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

感觉可以放到安全里面了

Copy link
Member Author

Choose a reason for hiding this comment

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

这个还是单独放一章吧,很多内容是配置反向代理的,不算安全相关

Copy link
Member

@atian25 atian25 Apr 11, 2019

Choose a reason for hiding this comment

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

嗯,可以是单独文章,不过回头重构的文档里面我放到安全目录,而不是在教程目录。新文档里面的安全是拆成多个文章了。

这里可以先这样。

---

一般来说我们的服务都不会直接接受外部的请求,而会将服务部署在接入层之后,从而实现多台机器的负载均衡和服务的平滑发布,保证高可用。

在这个场景下,我们无法直接获取到真实用户请求的连接,从而无法确认用户的真实 IP,请求协议,甚至请求的域名。为了解决这个问题,框架默认提供了一系列配置项来让开发者配置,以便基于和接入层的约定(事实标准)来让应用层获取到真实的用户请求信息。

## 开启前置代理模式

通过 `config.proxy = true`,可以打开前置代理模式:

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

exports.proxy = true;
```

注意,开启此模式后,应用就默认自己处于反向代理之后,会支持通过解析约定的请求头来获取用户真实的 IP,协议和域名。如果你的服务未部署在反向代理之后,请不要开启此配置,以防被恶意用户伪造请求 IP 等信息。

### `config.ipHeaders`

开启 proxy 配置后,应用会解析 [X-Forwarded-For](https://en.wikipedia.org/wiki/X-Forwarded-For) 请求头来获取客户端的真实 IP。如果你的前置代理通过其他的请求头来传递该信息,可以通过 `config.ipHeaders` 来配置,这个配置项支持配置多个头(逗号分开)。

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

exports.ipHeaders = 'X-Real-Ip, X-Forwarded-For';
```

### `config.maxProxyCount`
Copy link
Member

Choose a reason for hiding this comment

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

这些配置是不是考虑加载一个 config.xx 上,全挂到根下,回头不好管理,和用户的冲突啥的

Copy link
Member Author

Choose a reason for hiding this comment

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

下个大版本可以统一整理一下

Copy link
Member

Choose a reason for hiding this comment

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

感觉可以考虑一波大版本了:

  1. 单进程
  2. config 异步
  3. 一些历史包袱抛掉


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

```
X-Forwarded-For: client, proxy1, proxy2
```

我们可以拿第一个作为请求的真实 IP,但是如果有恶意用户在请求中传递了 `X-Forwarded-For` 参数来伪造其在反向代理之后,就会导致 `X-Forwarded-For` 拿到的值不准确了,可以被用来伪造请求 IP 地址,突破应用层的一些 IP 限制。

```
X-Forwarded-For: fake, client, proxy1, proxy2
```

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

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

exports.maxProxyCount = 1;
```

### `config.protocolHeaders`

开启 proxy 配置后,应用会解析 [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) 请求头来获取客户端的真实访问协议。如果你的前置代理通过其他的请求头来传递该信息,可以通过 `config.protocolHeaders` 来配置,这个配置项支持配置多个头(逗号分开)。

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

exports.protocolHeaders = 'X-Real-Proto, X-Forwarded-Proto';
```

### `config.hostHeaders`

开启 proxy 配置后,应用仍然还是直接读取 `host` 来获取请求的域名,绝大部分反向代理并不会修改这个值。但是也许有些反向代理会通过 [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) 来传递客户端的真实访问域名,可以通过在 `config.hostHeaders` 中配置,这个配置项支持配置多个头(逗号分开)。

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

exports.hostHeaders = 'X-Forwarded-Host';
```