闲来无事,再水一篇。
何为XFF?该参数怎么产生?
X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。 Squid 缓存代理服务器的开发人员最早引入了这一HTTP头字段,并由IETF在HTTP头字段标准化草案[1]中正式提出。
普通建站时,我们可以通过REMOTE_ADDR获取网站访客IP信息。但是当我们的网站部署在CDN后时,用户的请求到达源站服务器之前需要先通过CDN服务器,此处REMOTE_ADDR
获取的就是CDN回源服务器的地址。XFF参数是由CDN服务器转发原始请求时并加上。
例如自定义的nginx反向代理配置:
location / {
proxy_pass https://huai.pub;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
}
安全性问题与解决方案
伪造
问题:
由于该参数是直接暴露在http头部的。恶意用户就可以直接在请求头对该字段进行伪造。就造成了该参数的不可信任性。
解决:
该参数是公用的。我们可以通过使用私有参数来传递用户的真实IP地址。比如CLoudFlare使用的
CF-Connecting-IP
标头。我们在自建CDN时也可以使用私有参数来防止XFF伪造。也有其他公共CDN支持这类自定义表头,未作深入了解。注入
问题:
注入建立在伪造之上。很多情况下,需要将访客IP插入数据库统计。由于XFF的可伪造性,获取IP处的功能也容易被开发疏忽,从而不对此处进行安全化处理,会造成SQL注入问题。
解决:
此处拿了帝国CMS的相关写法。以供参考。
function GetIP(){
if(getenv('HTTP_CLIENT_IP')&&strcasecmp(getenv('HTTP_CLIENT_IP'),'unknown'))
{
$ip=getenv('HTTP_CLIENT_IP');
}
elseif(getenv('HTTP_X_FORWARDED_FOR')&&strcasecmp(getenv('HTTP_X_FORWARDED_FOR'),'unknown'))
{
$ip=getenv('HTTP_X_FORWARDED_FOR');
}
elseif(getenv('REMOTE_ADDR')&&strcasecmp(getenv('REMOTE_ADDR'),'unknown'))
{
$ip=getenv('REMOTE_ADDR');
}
elseif(isset($_SERVER['REMOTE_ADDR'])&&$_SERVER['REMOTE_ADDR']&&strcasecmp($_SERVER['REMOTE_ADDR'],'unknown'))
{
$ip=$_SERVER['REMOTE_ADDR'];
}
$ip=addslashes(preg_replace("/^([\d\.]+).*/","\\1",$ip));
return $ip;
}
另外。True-Client-IP、X-Forwarded-For、X-Client-Ip、X-Real-Ip、True-Client-IP等都属同类。不再赘述。