多重代理时如何防止伪造X-Forwarded-For且获取真实IP

当我们给网站使用例如CDN,Nginx或Varnish等缓存服务时,为了获取访客的真实IP,大多数会地把访客的真实IP赋值给X-Forwarded-For(下文简称XFF)。

但是因为XFF是个HTTP请求头,也就是最前面带有http_,因此这类http信息就可以被伪造。

127.0.0.1

 

 

其实根据实际使用情况判断是否需要获取XFF内容就不会出现这些问题。

拿Nginx的反代理(Proxy模块)功能来说,有人会把$proxy_add_x_forwarded_for变量的内容传给后端作为用户的真实IP。

Nginx对该变量的处理非常智能,当有XFF传过来时,Nginx就会自动把Nginx服务器的IP加到原来的XFF最后面,再发给后端。

这智能也带来了问题,如果访客自己伪造了一个XFF变量内容,那样后端服务器所获取的访客IP也是假的,给不怀好意的人有机可乘……

对于最前端来说,访客IP的变量只有一个是真实且无法伪造的——$remote_addr,此变量最前面不带有http_。

对于使用了Nginx,Varnish之类的做前端,把$remote_addr(Varnish的变量名为client.ip)作为访客IP是最明智的选择。

Nginx:

Varnish:

另外,使用Varnish的朋友也需注意下默认的XFF处理方式:

可以看出,Varnish的默认对XFF处理方式和Nginx Proxy模块的$proxy_add_x_forwarded_for基本一样。也一样存在XFF欺骗的问题。

如果没有使用CDN,个人建议把判断XFF是否有内容的代码去掉,直接获取remote_addr传给后端:

当然,前面所提及的只是最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最最简单的情况。

假设有一个网站使用这样的环境:PHP解析引擎为Apache,Apache前面有一个Nginx做缓存,Nginx前面还有一个Varnish做缓存,Varnish前面又加一个内容分发网络(CDN,所有节点均使用Nginx),我如何实现在Apache处能获取到访客真实IP,且不会出现XFF欺骗的情况?

首先,要求后端服务器,均不能直接访问,只允许通过CDN服务器访问!否则可能出现欺骗XFF的情况。

最前端——CDN节点的Nginx以$remote_addr变量作为访客的真实IP!这是保证不被欺骗XFF的关键:

Varnish处,获取从CDN节点传来的XFF内容,赋值给XFF,传给后面的Nginx:

Nginx处,如果要使用limit_req模块,或记录日志等功能,需要realip模块,设置真实IP来源于Varnish服务器的IP,并告诉Real模块,哪个变量储存着访客的真实IP,然后把Varnish传过来带有真实IP的XFF赋值给XFF传给Apache:

Apache处,需要安装rpaf模块,并告诉rpaf模块,安装varnish,nginx的服务器IP和储存访客真实IP的变量:

可见,从最前端的CDN节点到最后端的Apache,变量XFF的一直没变,一直都是只有访客的真实IP,如果Nginx处只是缓存,甚至连realip模块都不需要,直接就把XFF传送给Apache,这极大的简化了后端的处理,不仅能获取到访客的真实IP地址,也不会出现伪造XFF的问题。

最后我顺便提一下,X-Forwarded-For只是个变量名,你完全可以改成其它你喜欢的名字,我全文都用了X-Forwarded-For,只是顺应大多数人长久以来的使用习惯……

LNMPV0.3 Stable For Ubuntu 12.*/Debian 6/Debian7/CentOS6 32Bit or 64Bit

从今天开始,LNMPV的网站正式启用,以后新版均在http://www.mke2fs.com发布

 

LNMPV 0.2 Stable:

昨天发布了LNMPV 0.1测试版,感谢http://imlonghao.com/这个勇敢的小白,试用了我的LNMPV0.1,告知了我很多BUG,经过昨晚的努力,终于解决了。

另外还要感谢单手摘JJ,经过他昨晚的提醒,让我恍然大悟,发现可以一站一POOL来实现PHP以特定的用户身份执行。从而解决跨站问题。

本次更新:

1 )使用sock方式链接PHP-FPM

2 )添加可选的一站点一POOL的功能

3 )修改PHP-FPM的进程上限

4 )修改PHP-FPM的默认执行身份

5 )修复部分过分精简的Debian 6无法安装的问题

many……

使用环境:

CentOS 6 32Bit,CentOS6 64Bit,Ubuntu 12.04 32Bit,Ubuntu 12.04 64Bit,Ubuntu 12.10 32Bit,Ubuntu 12.10 64Bit,Debian 6 32Bit,Debian 6 64Bit

将会安装:

Nginx 1.4.1

PHP5.3(Debian6,Ubuntu12.04,CentOS 6)或PHP5.4(Ubuntu12.10)

MySQL5.5

Varnish3.0.4

Memcached

我们Nginx所包含的模块:

不知道有没有列全,反正是挺多的了,具体有什么用,怎样用,Nginx WIKI欢迎您……

完美解决PHP跨站问题……

安装耗时:使用Ubuntu/Debian且网络好的大概需要一首背对背拥抱的时间,使用CentOS,甚至地处墙厚的地理位置,服务器配置太低,网速太慢,大概需要一首情歌王(或许更长)的时间……

安装以及使用教程:

没有wget的同志执行这个:

CentOS 6.*:

Ubuntu12.* or Debian 6

这里三选一(LNMPV0.1请到下面找):

zip包:

tar.gz包:

tar.bz2包:

 安装:

For CentOS 6.*:

For Ubuntu 12.*:

For Debian 6:

CentOS 6安装时需要输入MySQL密码:

CentOS6 Install

 

如果回车跳过,则安装后密码为root。

 

Ubuntu 12.*/Debian6也要(好看多了):

Set MySQL Password

 

输入两次……

输入完密码,就开始自动安装了!

看到如下提示,祝贺你,一切完成:

Finish Install

探针地址:http://你服务器的IP:8910/tz.php

phpMyAdmin:http://你服务器的IP:8910/phpmyadmin

 

添加虚拟主机:

任何地方输入addhost:

另外提供一个删除网站的Shell Script:

执行完上面的命令后,在任意地方输入”delsite”,可看到如下提示:

Delsites

 

此处列出了您所添加的站点的配置文件,假设要删除360buy.com这个网站,就输入360buy.com.conf(不要忘了.conf),按Enter。

确定无误,就按任意键继续,本Shell Script会删除相应的配置文件并且重启相应的服务。

Finish

 

更多问题,请查看FAQ

 ==================================================

其它版本:

LNMPV0.1-Beta:

经过三天半的夜以继日地紧张劳作,LNMPV0.1-Beta终于问世了……

LNMPV,是Linux,Nginx,MySQL,PHP,Varnish的简称。

自己搭建过环境的都知道,Nginx是“资源节约型”的服务器程序,是个既要马儿跑,又要马儿吃草少的东西,但这仅仅是Nginx……

相信PHP-FPM进程到了上限,要排队访问,甚至502,503的场面,大家也不陌生。

此一键包,就是为了解决该问题而生的……

下载地址:

这里三选一:

zip包:

tar.gz包:

tar.bz2包:

 

FAQ

1 ) WordPress安装插件/主题时提示输入FTP账号密码:

如果添加虚拟主机时没有使用以不同用户身份运行PHP,就执行:

如果添加虚拟主机时对该站点使用了不同用户身份运行PHP,则执行:

 

2 )关于Rewrite(重写),就是伪静态规则,可以加入到:

里面,然后重启nginx:

3 ) 关于8910端口的页面:

本人建议大家更改该页面的端口:

把listen 8910;改成其他不易被猜到的端口。

同时可使用密码控制访问:

执行后访问:8910的默认用户名是:admin,密码是:passwd

 

4 ) 关于FTP:

木有!用SFTP吧,账号是root,密码是你root账号的密码……

关于控制面板:

木有!!!玩Linux,控制台就是你的控制面板!

有待添加……

 

如果安装失败,或者安装过程出现些什么错误,请把安装目录下的log文件通过邮件方式发到我的邮箱:e”at”yzs.me

有什么好的建议,或者反映BUG的,也可以通过邮件联系我。

 

下个版本打算加入可自定义每个站点的缓存时间的功能。:8910的首页开发中……

Varnish(前)+Nginx(中)时,让Apache(后)获取用户真实IP(多重代理)

不得不说我有点问题,网站一个Apache+Varnish不够,还要在Apache和Varnish之间插入个第三者——Nginx。

因为某些需要,也给该服务器上的个别网站上了CDN。
Apache做后端,前面多一个Nginx Proxy Cache+Varnish,获取用户的真实IP不难,只需给Apache上一个rpaf模块就行了,然后让Varnish处理XFF的内容就好了:

无CDN的情况下访问网站,可以正确获取到用户的真实IP。

最近给网站上多了一个CDN,rpaf模块就显得无能为力了。因此,这几天一直苦恼如何让我的网站获取用户真实IP。
问了下那家CDN的客服,给了我这个回答:
当使用CDN后,网站服务器访问日志中的IP地址都将记录为CDN服务器的官方IP。您可以通过下列方式获取访问用户的原始IP:
ASP
Request.ServerVariables(“HTTP_X_FORWARDED_FOR”)
PHP
$_SERVER[“HTTP_X_FORWARDED_FOR”]
JSP
request.getHeader(“HTTP_X_FORWARDED_FOR”)

似乎是要我修改我的网站的代码吧,不过这指标不治本,况且Ioncube加密后的,修改是没什么可能的了,问他们能否修改Nginx配置文件实现,不理我了……

看来还是得靠自己。他们既然能把那些代码发来,就证明他们的cdn服务器把真实IP存放在了HTTP_X_FORWARD_FOR里面,那么让nginx处理一下CDN服务器发来的xff的内容就行了了。

首先,取消Varnish处理XFF,把CDN传输的XFF直接交给Nginx处理,也就是注释掉以下内容:

然后在nginx的对应域名的setver层的location /层加进一行代码:

重启Nginx,打开探针看了看,终于正常了……

PHP探针