Cloudflare下取得访客真实IP

众所周知,当网站接入CDN加速后,部分程序例如Typecho获取到的IP就不再是访客真实IP了。在这种情况下,如果需要获得访客的真实IP,应该如何处理呢?

Main

本博客接入了Cloudflare,然而我早就忘记了接入各大CDN后都会遇到的一个坑(见上文),而CF在这方面又有一定的特性,于是就记录一下解决问题的过程。

config.inc.php中添加如下代码:

/** 设置真实IP */
if(isset($_SERVER['HTTP_CF_CONNECTING_IP']))$_SERVER['REMOTE_ADDR']=$_SERVER['HTTP_CF_CONNECTING_IP'];
else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))$_SERVER['REMOTE_ADDR']=end(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']));

压行功底见长 Orz

简单解说:
CDN服务按照行业规范一般会设置$_SERVER['HTTP_X_FORWARDED_FOR'],保存来源IP,当层数多于一层时以半角逗号,分隔。
CF有一个特性,即它还会发送$_SERVER['HTTP_CF_CONNECTING_IP']保存请求IP。由于我用的是CF,所以我优先获取这个参数保存的IP。

简单的测试

Warning

CF特有的$_SERVER['HTTP_CF_CONNECTING_IP']相对安全,而$_SERVER['HTTP_X_FORWARDED_FOR']则有一定的安全隐患。下面应用Python进行一点测试。

尝试篡改CF-CONNECTING-IP

这两个参数都是由请求头提交的,即我们可以构造请求头。参考下面的Python3代码:

import requests
import json
headers={'CF-CONNECTING-IP':'0.0.0.0'}
rs=requests.get('https://www.wuxian.gq/test-ip.php',headers=headers)
print(rs.text)

然而CF并不上当,直接丢出警告:
尝试篡改CF-CONNECTING-IP

相对安全。

尝试篡改X-FORWARDED-FOR

同样构造请求头:

import requests
import json
headers={'X-FORWARDED-FOR':'0.0.0.0'}
rs=requests.get('https://www.wuxian.gq/test-ip.php',headers=headers)
print(rs.text)

这一次的情况并不容乐观:
尝试篡改X-FORWARDED-FOR

可以看见我们构造的0.0.0.0成功传入了$_SERVER['HTTP_X_FORWARDED_FOR']预定义变量,即常规的直接把$_SERVER['HTTP_X_FORWARDED_FOR']当做真实IP的做法并不可取甚至有SQL注入风险,需要格外注意。

$_SERVER['HTTP_X_FORWARDED_FOR']并不安全!

总结

Web编程的原则是不能相信用户提交的数据,一定要在各个环节做好过滤,即使是对于IP地址也决不可放松。
如果CDN有其特有的访客IP储存方式,且相对安全,应当首先利用CDN的特性,避免不必要的麻烦。

最后修改:2019 年 08 月 01 日 10 : 08 AM
欢迎投食喵 ~

发表评论