How to get “real” ip in proxy server?

作者:杨润炜
日期:2016/7/27 17:10

一般我们会在搭建代理服务器来转发到具体的应用,在这些应用里,怎样读取到代理之前的客户端ip呢?下面以nignx和koa举例。

代理服务器端

首先客户端的请求到达nginx代理服务器,我们可以通过设置headers的X-Forwarded-For来记录客户端ip,这是http的扩展头部,用来表示HTTP请求端的真实IP。
具体配置示例如下:

  1. location / {
  2. ...
  3. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  4. ...
  5. }
X-Forwarded-For格式讲解

这一HTTP头一般格式如下:
X-Forwarded-For: client1, proxy1, proxy2
其中的值通过一个 逗号+空格 把多个IP地址区分开, 最左边(client1)是最原始客户端的IP地址, 代理服务器每成功收到一个请求,就把请求来源IP地址添加到右边。 在上面这个例子中,这个请求成功通过了三台代理服务器:proxy1, proxy2 及 proxy3。请求由client1发出,到达了proxy3(proxy3可能是请求的终点)。请求刚从client1中发出时,XFF是空的,请求被发往proxy1;通过proxy1的时候,client1被添加到XFF中,之后请求被发往proxy2;通过proxy2的时候,proxy1被添加到XFF中,之后请求被发往proxy3;通过proxy3时,proxy2被添加到XFF中,之后请求的的去向不明,如果proxy3不是请求终点,请求会被继续转发。

nginx中关于$proxy_add_x_forwarded_for的讲解

$proxy_add_x_forwarded_for
the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma. If the “X-Forwarded-For” field is not present in the client request header, the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable.

nginx会往接收到的http headers X-Forwarded-For中添加$remote_addr(此次请求的ip地址)。

所以X-Forwarded-For中最左边的ip地址便是我们想要的客户端ip。

应用端

node.js的koa框架中,使用ctx.ip来表示http请求的ip。但此时http请求是通过我们前面搭建的代理服务器转发来的,此时如果没有告诉koa,ctx.ip便显示代理服务器的ip。如果我们能告诉koa去读取headers信息中的X-Forwarded-For信息,并读取第一个ip,那便是“真正的”客户端ip了。
具体看看koa源码中怎样实现的:

request.js
  1. module.exports = {
  2. ...
  3. get ip() {
  4. return this.ips[0] || this.socket.remoteAddress || '';
  5. },
  6. get ips() {
  7. var proxy = this.app.proxy;
  8. var val = this.get('X-Forwarded-For');
  9. return proxy && val
  10. ? val.split(/\s*,\s*/)
  11. : [];
  12. },
  13. ...
  14. }

从源码中可以看出,如果我们设置了app.proxy的值为true,那koa便能实现上述需求。
具体设置如下:

  1. var Koa = require('koa');
  2. var app = new Koa();
  3. app.proxy = true; // 设置一些proxy header 参数会被加到信任列表中

另外在express中,可以通过下面形式设置信任proxy server信息:

  1. app.enable('trust proxy');

这样设置之后,便可以通过如下形式来获取到所需的ip了:

  1. app.use(function *() {
  2. console.log(this.ip);
  3. });

注意

因为X-Forwarded-For可以随意更改,而且http请求到我们代理服务器时,往往会经过多层代理,如果某个代理服务器“不诚实”地修改X-Forwarded-For信息, 那么我们获取到的ip有可能并不是操作者的ip。所以获取客户端请求ip的真实性不高,只能作为参考。

参考

X-Forwarded-For维基百科
ngx_http_proxy_module

感谢您的阅读!
如果看完后有任何疑问,欢迎拍砖。
欢迎转载,转载请注明出处:http://www.yangrunwei.com/a/66.html
邮箱:glowrypauky@gmail.com
QQ: 892413924