discuz获取真实ip的方法是这个:
source/class/discuz/discuz_application.php
也就是说默认用REMOTE_ADDR,如果有HTTP_CLIENT_IP或HTTP_X_FORWARDED_FOR,则用相应的指定的IP地址。
这个对于用ip来限制重试密码的方式来说,很危险,伪造一个CLIENT_IP或者X_FORWARDED_FOR就可以让discuz认为的独立的ip,从而脱离限制。
discuz也没有白名单机制去限制这两个参数的使用,所以是个很危险的漏洞。
防御方式:对使用CLIENT_IP或者X_FORWARDED_FOR限制
如果明确不使用代理方式部署服务器,那可以考虑禁用这两个参数。
如果用代理的方式部署,可以实施白名单机制。
PHP修改代码即可,判别REMOTE_ADDR白名单再启用这两个参数。
Nginx也可以有白名单的方式,编译需要添加参数:
--with-http_realip_module
使用说明:http://nginx.org/en/docs/h...
可以对比一下几个方式搭配:
1 不使用realip_module
2 使用realip_module
客户端模式:
A 伪造client-ip直接访问目标服务器
B 伪造client-ip访问代理服务器
C 代理服务器不在realip_module白名单
为此,我们需要先修改PHP代码,以便获知PHP获得的参数:
测试组合结果:
域名和ip因为隐私做了替换
测试结果说明什么问题?
1A 客户端ip 和设定的ip都收到
1B 代理ip和客户端ip
2A 客户端ip和设定的ip
2B 客户端ip和客户端ip
2C 代理ip和客户端ip
说明,realip_module传递给PHP后端REMOTE_ADDR就是合法的CLIENT_IP,而CLIENT_IP却没有清空
那问题来了,它没法解决discuz检查CLIENT_IP的漏洞,如果检查就没戏
所以,PHP加一份白名单很有必要哦!
原创内容如转载请注明:来自 阿权的书房
source/class/discuz/discuz_application.php
private function _get_client_ip() {
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
}
return $ip;
}
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
}
return $ip;
}
也就是说默认用REMOTE_ADDR,如果有HTTP_CLIENT_IP或HTTP_X_FORWARDED_FOR,则用相应的指定的IP地址。
这个对于用ip来限制重试密码的方式来说,很危险,伪造一个CLIENT_IP或者X_FORWARDED_FOR就可以让discuz认为的独立的ip,从而脱离限制。
discuz也没有白名单机制去限制这两个参数的使用,所以是个很危险的漏洞。
防御方式:对使用CLIENT_IP或者X_FORWARDED_FOR限制
如果明确不使用代理方式部署服务器,那可以考虑禁用这两个参数。
如果用代理的方式部署,可以实施白名单机制。
PHP修改代码即可,判别REMOTE_ADDR白名单再启用这两个参数。
Nginx也可以有白名单的方式,编译需要添加参数:
--with-http_realip_module
使用说明:http://nginx.org/en/docs/h...
可以对比一下几个方式搭配:
1 不使用realip_module
2 使用realip_module
客户端模式:
A 伪造client-ip直接访问目标服务器
B 伪造client-ip访问代理服务器
C 代理服务器不在realip_module白名单
代理服务器设置
proxy_set_header CLIENT-IP $remote_addr;
proxy_set_header CLIENT-IP $remote_addr;
为此,我们需要先修改PHP代码,以便获知PHP获得的参数:
private function _get_client_ip() {
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_GET['debug_ip'])) {
exit('REMOTE_ADDR:'.$ip.' / CLIENT_IP:'.$_SERVER['HTTP_CLIENT_IP'].' / X_FORWARDED_FOR:'.$_SERVER['HTTP_X_FORWARDED_FOR']."\n");
}
$white_lists = array(
'60.191.x.y',
'123.157.x.y',
'222.187.x.y',
'121.40.x.y',
);
if (!in_array( $ip, $white_lists)) {
return $ip;
}
if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
}
return $ip;
}
$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_GET['debug_ip'])) {
exit('REMOTE_ADDR:'.$ip.' / CLIENT_IP:'.$_SERVER['HTTP_CLIENT_IP'].' / X_FORWARDED_FOR:'.$_SERVER['HTTP_X_FORWARDED_FOR']."\n");
}
$white_lists = array(
'60.191.x.y',
'123.157.x.y',
'222.187.x.y',
'121.40.x.y',
);
if (!in_array( $ip, $white_lists)) {
return $ip;
}
if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
}
return $ip;
}
测试组合结果:
域名和ip因为隐私做了替换
引用
1A
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw3.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:2.3.4.5 / X_FORWARDED_FOR:
1B
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:222.187.x.y / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:
2A
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw3.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:2.3.4.5 / X_FORWARDED_FOR:
2B
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:
2C 222.187.x.y 不在nginx的白名单的情况
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:222.187.x.y / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw3.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:2.3.4.5 / X_FORWARDED_FOR:
1B
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:222.187.x.y / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:
2A
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw3.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:2.3.4.5 / X_FORWARDED_FOR:
2B
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:114.243.204.152 / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:
2C 222.187.x.y 不在nginx的白名单的情况
curl -H "host:www.aslibra.com" -H "CLIENT-IP:2.3.4.5" "dyw4.aslibra.com/?debug_ip=1"
REMOTE_ADDR:222.187.x.y / CLIENT_IP:114.243.204.152 / X_FORWARDED_FOR:
测试结果说明什么问题?
1A 客户端ip 和设定的ip都收到
1B 代理ip和客户端ip
2A 客户端ip和设定的ip
2B 客户端ip和客户端ip
2C 代理ip和客户端ip
说明,realip_module传递给PHP后端REMOTE_ADDR就是合法的CLIENT_IP,而CLIENT_IP却没有清空
那问题来了,它没法解决discuz检查CLIENT_IP的漏洞,如果检查就没戏
所以,PHP加一份白名单很有必要哦!
原创内容如转载请注明:来自 阿权的书房
收藏本文到网摘