php 在电商类型的项目中,防止机器人伪造ip以及恶意刷单

最近这几天,总是被人捣乱恶意刷单,查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;
        }
    }
}

你可能感兴趣的:(php)