Discuz! X(所有版本) 的默认代码允许攻击者任意伪造 IP,伪造 IP 的方法请看 3 楼。
因为DZ在设计上,是优先获取代理IP,然后才会检测代理服务器是否将用户真实IP传输过来,也就是说获取代理IP优先于用户真实IP。
代码如下:
🧒🧢🧻😶👁
- source/class/discuz/discuz_application.php
全屏查看-  private function _get_client_ip() {
 
-                 // 这个 ip 地址没问题, 是真实用户的
 
-                 $ip = $_SERVER['REMOTE_ADDR'];
 
-                 
 🚂🥛📶🦜
-                 if (!$this->config['security']['onlyremoteaddr']) {
 
 
-                         // $_SERVER['HTTP_CLIENT_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'];
 
 
-                         // $_SERVER['HTTP_X_FORWARDED_FOR'] 这个也可以伪造
 
-                         
 
-                         } 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 == '::1' ? '127.0.0.1' : $ip;
 
-         }
 👦🎺😋🙌
2020年1月19日更新:
这个文件中的
-  $_config['security']['onlyremoteaddr'] = 1;
🧠💈🔪🈴🐢
只在 Discuz X3.5 中有效
参见:
https://gitee.com/ComsenzDiscuz/DiscuzX/pulls/342
------------------------沙雕分割线-------------------------------
🧑🌾🦺🗡🙃🤌
我也不知道为什么这样设计代码,可能是考虑小白站长使用 cdn 后的问题?
因为我已经用 nginx 转换了代理(CDN)的 ip 地址,所以修改成如下:
全屏查看-  private function _get_client_ip() {
 
-                 $ip = $_SERVER['REMOTE_ADDR'];🧑🌾👚💰😤👀
 
-                 return $ip == '::1' ? '127.0.0.1' : $ip;
 
- /*                
 
-                 if (!$this->config['security']['onlyremoteaddr']) {
 
-                         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 == '::1' ? '127.0.0.1' : $ip;
 👍🌦🍒🅿🦮
- */
 
-         }
 
 $_SERVER['REMOTE_ADDR'] 获取到用户 ip 之后 ,直接返回,不执行后面的代码了。
🖕🌦🍧🈷🐋如果你没使用 CDN,这样修改就可以了。如果使用了 CDN,那么还要修改 nginx,把访客的 ip 转发,参考 
https://www.guhei.net/post/jb1759