Redis之hash使用-----短信接口限制IP访问次数以及手机号访问次数
2016-04-12 10:05:51 小德 Redis 访问次数 2236

网站注册页一般会暴露短信接口,从安全角度的考虑应该对短信接口做相应的保护。常见的方式有


1、动态注册验证码:

        a、短信可触发条件为短信验证码正确;

        b、调用短信接口前再次验证短信验证码;

        c、调用短信接口前验证HTTP_Refer;

2、限制IP以及单个手机号的访问次数

    策略:每次发送短信后将相关手机号,IP信息以及首次发送的时间已经发送的次数存入Redis,每次发送前 取出Redis中的相关信息 进行比对验证,如果已超过策略则提醒,并且不再接受短信接口的请求调用。每次发送短信后将Redis中的相关信息进行调整,分为首次的非首次。

    Redis存储读取代码:

$info['FirstSendTime'] = '第一次发送时间';
    $info['haveSendTimes'] = '已经发送的次数';
    hset('sms','13112345678',$info) ;  
      $info =  hget('sms','13112345678); 
    hset('ip','127.0.0.1',$info);
    $info =  hget('sms','127.0.0.1');


    实例:

  //一天内 发短信对手机号和IP进行限制
        private function SmsCheck($phone){
            $sms_config = C('SmsConfig');
            // IP限制
            $ip_access = $this->_ipLimit($sms_config);
            //读取Redis手机号的发送次数
            $sms_collect = Db_Redis::hget_json('SMS', $phone);
            // 如果在reids中有数据,则执行策略
            empty($sms_collect) || $re = $this->_doStrategy($sms_collect, $sms_config);
            //通过验证,重新设置策略
            $this->_resetStrategy($sms_collect, $ip_access,$phone);
        }
        // 重置 $sms redis中保存的短信信息 $ipAccess redis中保存的IP地址信息
        private function _resetStrategy($sms = '', $ipAccess = '',$phone){
            // 重置IP数据
            $this->_resetIp($ipAccess);
            //如果在redis中无数据,则初始化数据
            if ( empty($sms) )
            {
                $sms = $this->_initsms();
            }
            else
            {
                // 当前时间 - 第一次发送时间大于24小时,则需重新初始化
                if ( ($_SERVER['REQUEST_TIME'] - $sms['firstSendTime']) > 24 * 3600 )
                {
                    $sms = $this->_initsms();
                }
                else
                {
                    // 当前时间 - 第一次发送时间小于24小时,则将发送数量进行相加
                    $sms['sendNumber']++;
                }
            }
            Db_Redis::hset('SMS', $phone, json_encode($sms));
        }
        //重置IP
        private function _resetIp($ipAccess = array())
        {
            // IP重置策略
            if ( empty($ipAccess) )
            {
                // IP第一次使用
                $ipAccess = array(
                    'firstAccessTime' => $_SERVER['REQUEST_TIME'],
                    'access_ip_number' => 1
                );
            }
            else
            {
                # IP非第一次使用,操作时间已经过了24小时
                if ( ($_SERVER['REQUEST_TIME'] - $ipAccess['firstAccessTime']) > 24 * 3600 )
                {
                    $ipAccess = array(
                        'firstAccessTime' => $_SERVER['REQUEST_TIME'],
                        'access_ip_number' => 1
                    );
                }
                else
                {
                    // 操作时间未过24小时
                    $ipAccess['access_ip_number']++;
                }
            }
            Db_Redis::hset('AccessIp',USER_IP, json_encode($ipAccess));
        }
        //充值 短信次数
        private function  _initsms(){
            return array(
                'sendNumber' => 1,
                'firstSendTime' => $_SERVER['REQUEST_TIME'],
            );
        }
        //IP限制
        private function _ipLimit($config)
        {
            # 获取IP地址的访问次数
            $access_number = Db_Redis::hget_json('AccessIp', USER_IP);
            # 如果请求时间 - 第一次访问时间 在24小时内发送短信的数量超过配置数量,则提示短信发送数量已经超额
            if ( ($_SERVER['REQUEST_TIME'] - $access_number['firstAccessTime']) < 24 * 3600 )
            {
                if ( $access_number['access_ip_number'] >= $config['ip_max_times'] )
                {
                    msg('IP您今天发送的短信已超标,请在24小时后再进行发送');
                }
            }
            return $access_number;
        }
        //执行策略 $collect=> Redis中保存的数据信息 $config=>配置的限制信息
        private function _doStrategy($collect,$config) {
            // 如果在一天内发送的数量超过配置数量,则提示超额发送
            if ( ($_SERVER['REQUEST_TIME'] - $collect['firstSendTime']) < 24 * 3600 )
            {
                if ( $collect['sendNumber'] >= $config['phone_max_times'] )
                {
                    msg('smg您今天发送的短信已超标,请在24小时后再进行发送');
                }
            }
        }