最近这几天,总是被人捣乱恶意刷单,查ip发现都是无效ip,于是查找了资料后,再根据个人的想法提出可行的解决方案。
首先是获取ip的方法:
/** * 获取客户端IP地址 *
来源:ThinkPHP *
"X-FORWARDED-FOR" 是代理服务器通过 HTTP Headers 提供的客户端IP。代理服务器可以伪造任何IP。 *
要防止伪造,不要读这个IP即可(同时告诉用户不要用HTTP 代理)。 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @param boolean $adv 是否进行高级模式获取(有可能被伪装) * @return mixed */ function get_client_ip($type = 0, $adv = false) { $type = $type ? 1 : 0; static $ip = NULL; if ($ip !== NULL) return $ip[$type]; if ($adv) { if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); $pos = array_search('unknown', $arr); if (false !== $pos) unset($arr[$pos]); $ip = trim($arr[0]); }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (isset($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } } elseif (isset($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } // IP地址合法验证, 防止通过IP注入攻击 $long = sprintf("%u", ip2long($ip)); $ip = $long ? array($ip, $long) : array('0.0.0.0', 0); return $ip[$type]; } /** * 获得用户的真实IP地址 *
来源:ecshop *
$_SERVER和getenv的区别,getenv不支持IIS的isapi方式运行的php * @access public * @return string */ function real_ip() { static $realip = NULL; if ($realip !== NULL) { return $realip; } if (isset($_SERVER)) { if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); /* 取X-Forwarded-For中第一个非unknown的有效IP字符串 */ foreach ($arr AS $ip) { $ip = trim($ip); if ($ip != 'unknown') { $realip = $ip; break; } } } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { $realip = $_SERVER['HTTP_CLIENT_IP']; } else { if (isset($_SERVER['REMOTE_ADDR'])) { $realip = $_SERVER['REMOTE_ADDR']; } else { $realip = '0.0.0.0'; } } } else { if (getenv('HTTP_X_FORWARDED_FOR')) { $realip = getenv('HTTP_X_FORWARDED_FOR'); } elseif (getenv('HTTP_CLIENT_IP')) { $realip = getenv('HTTP_CLIENT_IP'); } else { $realip = getenv('REMOTE_ADDR'); } } // 使用正则验证IP地址的有效性,防止伪造IP地址进行SQL注入攻击 preg_match("/[\d\.]{7,15}/", $realip, $onlineip); $realip = !empty($onlineip[0]) ? $onlineip[0] : '0.0.0.0'; return $realip; }
与thinkphp5内置的ip()方法相比使用real_ip()方法可以有效避免恶意的无效ip。
接着针对恶意刷单,当时一天经常被刷十几万单,完全避免是不可能的,只能说是减少这个ip的下单次数 并把这个ip加入到黑名单里。
* 思路 1.获取当前时间和当前时间前一分钟的时间戳 以及 2.当前时间和当前时间前一天时间戳 * 对于1=> 如果在这个时间范围内的当前ip下单超过5单 将这个ip加入黑名单 * 对与2=> 如果在24小时内的当前ip下单超过20单 将这个ip加入黑名单
$ip=$request->real_ip();
//当前时间 $nowTime = time();
//当前时间的前1分钟 $twoTime = time() - 60;
//当前时间的前24小时 $dayTime = time() - 3600*24; $condition = [ 'ip' => $ip, 'create_time' =>array('between',array($twoTime,$nowTime)), ]; $dayCondition = [ 'ip' => $ip, 'create_time' =>array('between',array($dayTime,$nowTime)), ]; //当前时间 一分钟半的时间内 刷单超过5单的,自动加入黑名单 $ipBad = Db('GoodsOrder')->field('ip,count(*) as count')->where($condition)->find(); //在第二天零点之前 刷单超过20单的,自动加入黑名单 $dayIpBad = Db('GoodsOrder')->field('ip,count(*) as count')->where($dayCondition)->find(); if($ipBad['count'] > 4 || $dayIpBad['count'] > 20){ $not_ip = Db::name('config')->where(array('uid'=>1))->field('ip_list')->find(); $not_ip = $not_ip['ip_list']; $not_ip = $not_ip.';'.$ip;
//将黑名单ip更新到后台
Db::name('config')->where(array('uid'=>1))->update(['ip_list'=>$not_ip]); return false; }
然后让前台的控制器继承一个Base控制器,在这个控制器当中去判断当前用户的ip地址是否在黑名单里,在的话强制跳转到404页面
namespace app\index\controller; use think\Controller; use think\Request; use think\Db; class Base extends Controller{ public function _initialize(){ $request = Request::instance();
//获取当前域名 $domain = $request->domain(); $ipAddress = $request->ip();
// uid 权限 uid=1代表总后台 $uid = 1; $badIp = $web_config = Db::name('config')->field('ip_list')->where(array('uid' => $uid))->find(); $badIp = explode(';',$badIp['ip_list']); $isin = in_array($ipAddress, $badIp); if($isin){ $url = $domain . '/' . 'index/error/error404'; header("Location: $url"); exit; } } }