WEB程序获取客户端IP的方法有两种,一种是直接获取访问来源的IP,另一种是通过HTTP头中带的IP信息来获取。
前者获取的IP是直接接触的IP,既获取的永远都是最后一环的IP,如果用户使用了代理,就获取不到用户真实IP了。
后者获取的IP是“代理服务器”在HTTP头加上的信息,帮助识别或者标记IP路径,或者客户端的原始IP,但是HTTP头的信息是可控的,也就是说可伪造。
以PHP为例,PHP可以通过$_SERVER和getenv获取常量IP如下:
$_SERVER[‘REMOTE_ADDR‘];
$_SERVER[‘HTTP_CLIENT_IP‘];
$_SERVER[‘HTTP_X_FORWARDED_FOR‘];
getenv("HTTP_X_FORWARDED_FOR");
getenv("HTTP_CLIENT_IP");
getenv("REMOTE_ADDR");
其中 REMOTE_ADDR 就是上面提到的情况1,HTTP_CLIENT_IP 和 HTTP_X_FORWARDED_FOR 就是情况二。
对于一个完整的获取IP的功能来说,较为合理的是获取 HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP 等代理服务器标识的IP,若不存在则获取直接相连的 REMOTE_ADDR 。
但是这样做的安全隐患就是:X_FORWARDED_FOR 等信息是HTTP头中的字段,可以被修改(伪造)为任意字符串。假设一个业务情景是:将用户的IP存入数据库内,若先获取到了用户伪造的IP字符串,注入了SQL查询语句,造成了 SQL Inject 漏洞。
所以要么直接获取REMOTE_ADDR,要么对 HTTP_X_FORWARDED_FOR 等进行过滤(比如按格式来过滤,或者用正则来刨除除了‘点‘和‘数字‘以外其他字符)