业务防刷策略

一、背景及目标

基于现有业务,如各类活动投票、抽奖等用户行为,为了防止用户存在作弊刷票等问题,同时考虑到后期类似业务,据此建设业务层防刷机制。

目标是将损失降低同时让更多的用户受益。

二、实现方案

2.1 方案一

采用PHP在通用服务层封装类库,在odp框架中的控制层内进行防刷机制,防刷过程中的临时数据(如执行计数、冻结标志位等)采用redis进行存储

2.1.1 方案实现

遍历所有策略

基本策略流程

2.1.2 初始化配置

$config = array(
    'namespace' => __CLASS__, // 防刷命名空间:对不同的业务加以区分,进行计数的基准
    'context' => array( // 请求上下文
        'ip' => Bd_Log::getClientIp(), // 用户请求ip
    ),
    'strategy' => array( // 防刷策略列表
        array( // 防刷配置1
            'interval' => 5, // 持续时间
            'limit' => 500, // 执行次数
            'freeze' => 5*3600, //冻结5小时
        ),
    ),
);
$firewall = Utils_Firewall_Core::init($config);

2.1.3 调用方法

控制层加入防刷接入firewallMonitor

/**
 * @name Action_VoteProduct
 * @desc 投票
 * @author 满帅(manshuai@baidu.com)
 */
class Action_VoteProduct extends Ap_Action_Abstract
{
 
    /**
     * execute
     *
     * @return void
     */
    public function execute() {
        // init
        $response = array(
            'error_code' => 0,
            'error_msg'  => 'success',
        );
 
        // transmit to service
        try {
            // 防刷接入
            $this->firewallMonitor();
 
            // check permission
            $this->checkPermission();
 
            // load request
            $request = $this->getRequest();
 
            // load service
            $service = new Service_Page_XXXXXX();
            // execute
            $result = $service->doSometing($request->getPost());
 
            // response data
            $response['data'] = $result;
        } catch(Utils_Error $e) {
            // log exception
            Bd_Log::warning($e, $e->getErrNo());
 
            // package result
            $response['error_code'] = $e->getErrNo();
            $response['error_msg'] = $e->getErrStr();
        }
 
        // render json
        $this->renderJson($response);
 
        // log
        $this->log($response);
    }
 
    ... ...

 

业务防刷firewallMonitor示例

/**
 * 防刷策略
 *
 * @return void
 */
private function firewallMonitor()
{
    Utils_Firewall_Core::init(array(
        'namespace' => __CLASS__,
        'context' => array(
            'ip' => Bd_Log::getClientIp(),
        ),
        'strategy' => array(
            array(
                'interval' => 5, // 持续时间
                'limit' => 500, // 执行次数
                'freeze' => 5*3600, //冻结5小时
            ),
        ),
    ))->monitor();
}