闲来无事,再水一篇。

何为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;
        }

安全性问题与解决方案

  1. 伪造

    问题:

    由于该参数是直接暴露在http头部的。恶意用户就可以直接在请求头对该字段进行伪造。就造成了该参数的不可信任性。

    解决:

    该参数是公用的。我们可以通过使用私有参数来传递用户的真实IP地址。比如CLoudFlare使用的CF-Connecting-IP标头。我们在自建CDN时也可以使用私有参数来防止XFF伪造。也有其他公共CDN支持这类自定义表头,未作深入了解。

  2. 注入

    问题:

    注入建立在伪造之上。很多情况下,需要将访客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等都属同类。不再赘述。