phpBB3在Nginx反向代理中的X-Forwarded-ForIP检查
记录一下phpBB3对反向代理中的IP处理机制
处理几个phpBB3项目迁移, 部分运行场景转移到内网, 需要外网通过nginx/openresty之类的网关反向代理进行访问. 在网关处已经正确配置了远端IP的转发
location / { proxy_pass http://your_brilliant_website/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_intercept_errors on; }
在运行phpBB3的服务器上, 是通过Nginx + php-fpm 的方式处理PHP访问的, 经检查已经在$_SERVER中能看到正确的远端IP
$_SERVER['HTTP_X_FORWARDED_FOR'] 11.23.212.66 $_SERVER['HTTP_REMOTE_HOST'] 11.23.212.66 $_SERVER['HTTP_X_REAL_IP'] 11.23.212.66
但是在phpBB3中, sessions表里记录的IP依然是网关的内网IP.
查看了一下代码, 关联的代码在 forum/phpbb/session.php. IP部分取自$_SERVER['REMOTE_ADDR']仅对值进行了一些判断和处理. 注释里也说明了这样做的原因: forward_for太容易伪造.
// Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. $ip = htmlspecialchars_decode($request->server('REMOTE_ADDR')); $ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $ip)); /** * Event to alter user IP address * * @event core.session_ip_after * @var string ip REMOTE_ADDR * @since 3.1.10-RC1 */ $vars = array('ip'); extract($phpbb_dispatcher->trigger_event('core.session_ip_after', compact($vars))); // split the list of IPs $ips = explode(' ', trim($ip)); // Default IP if REMOTE_ADDR is invalid $this->ip = '127.0.0.1'; foreach ($ips as $ip) { if (function_exists('phpbb_ip_normalise')) { // Normalise IP address $ip = phpbb_ip_normalise($ip); if (empty($ip)) { // IP address is invalid. break; } // IP address is valid. $this->ip = $ip; // Skip legacy code. continue; } if (preg_match(get_preg_expression('ipv4'), $ip)) { $this->ip = $ip; } else if (preg_match(get_preg_expression('ipv6'), $ip)) { // Quick check for IPv4-mapped address in IPv6 if (stripos($ip, '::ffff:') === 0) { $ipv4 = substr($ip, 7); if (preg_match(get_preg_expression('ipv4'), $ipv4)) { $ip = $ipv4; } } $this->ip = $ip; } else { // We want to use the last valid address in the chain // Leave foreach loop when address is invalid break; } }
但是phpBB3也增加了对forwarded_for部分的记录和判断, 因此增加了一个字段forwarded_for, 以及对应的配置项forwarded_for_check, 这一项在管理员控制面板的"综合->安全设置->经过验证的 X_FORWARDED_FOR 字段头"中设置.
// if the forwarded for header shall be checked we have to validate its contents if ($config['forwarded_for_check']) { $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for)); // split the list of IPs $ips = explode(' ', $this->forwarded_for); foreach ($ips as $ip) { // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) { // contains invalid data, don't use the forwarded for header $this->forwarded_for = ''; break; } } } else { $this->forwarded_for = ''; }
开启后, 会在forwarded_for中记录这个IP, 并对这个IP启用封禁规则.
这里有对使用$_SERVER['HTTP_X_FORWARDED_FOR']和$_SERVER['REMOTE_ADDR']的安全性的详细讨论
https://stackoverflow.com/questions/3003145/how-to-get-the-client-ip-address-in-php- 上一篇:【学习笔记】LinuxGDM
- 下一篇:Linuxssh-keygen