PHP项目IP归属与风控

wen PHP项目 4

本文目录导读:

PHP项目IP归属与风控

  1. IP归属查询模块
  2. 风控系统模块
  3. 数据库迁移文件
  4. 使用示例

我将为您提供一个PHP项目中的IP归属查询与风控系统的实现方案,这个系统包含IP地理位置查询、风险评分、访问频率限制等功能。

IP归属查询模块

1 IP地理位置查询类

<?php
namespace App\Utils;
class IpLocation
{
    private $ipdbPath;
    private $ipdb = null;
    public function __construct($ipdbPath = null)
    {
        $this->ipdbPath = $ipdbPath ?? __DIR__ . '/../../data/ip2region.xdb';
    }
    /**
     * 获取IP地理位置信息
     */
    public function getLocation($ip)
    {
        // 支持多种数据源,按优先级获取
        $location = $this->getFromIp2Region($ip);
        if (!$location) {
            $location = $this->getFromApi($ip);
        }
        return $location;
    }
    /**
     * 使用ip2region离线数据库
     */
    private function getFromIp2Region($ip)
    {
        try {
            if (!file_exists($this->ipdbPath)) {
                return null;
            }
            // 使用XDB搜索引擎
            $searcher = new \Ip2Region();
            $result = $searcher->btreeSearch($ip);
            if ($result && isset($result['region'])) {
                $regions = explode('|', $result['region']);
                return [
                    'country' => $regions[0] !== '0' ? $regions[0] : '',
                    'region' => $regions[1] !== '0' ? $regions[1] : '',
                    'province' => $regions[2] !== '0' ? $regions[2] : '',
                    'city' => $regions[3] !== '0' ? $regions[3] : '',
                    'isp' => $regions[4] !== '0' ? $regions[4] : '',
                    'full_location' => $result['region']
                ];
            }
        } catch (\Exception $e) {
            // 记录日志
            error_log("IP查询失败: " . $e->getMessage());
        }
        return null;
    }
    /**
     * 使用在线API查询
     */
    private function getFromApi($ip)
    {
        // 防止内网IP查询
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            $url = "http://ip-api.com/json/{$ip}?lang=zh-CN";
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 5,
                CURLOPT_SSL_VERIFYPEER => false
            ]);
            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if ($httpCode === 200) {
                $data = json_decode($response, true);
                if ($data && $data['status'] === 'success') {
                    return [
                        'country' => $data['country'] ?? '',
                        'region' => $data['regionName'] ?? '',
                        'province' => $data['regionName'] ?? '',
                        'city' => $data['city'] ?? '',
                        'isp' => $data['isp'] ?? '',
                        'lat' => $data['lat'] ?? 0,
                        'lon' => $data['lon'] ?? 0,
                        'timezone' => $data['timezone'] ?? '',
                        'full_location' => "{$data['country']} {$data['regionName']} {$data['city']}"
                    ];
                }
            }
        }
        return null;
    }
    /**
     * 获取客户端真实IP
     */
    public function getClientIp()
    {
        $ip = '';
        // 检查HTTP代理头
        $headers = [
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_REAL_IP',
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR',
            'HTTP_X_CLUSTER_CLIENT_IP'
        ];
        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ipList = explode(',', $_SERVER[$header]);
                $ip = trim($ipList[0]);
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    break;
                }
            }
        }
        // 如果获取不到,使用REMOTE_ADDR
        if (empty($ip) && isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        return $ip;
    }
}

2 IP数据库更新脚本

<?php
namespace App\Console;
class UpdateIpDatabase
{
    private $downloadUrl = 'https://github.com/lionsoul2014/ip2region/raw/master/data/ip2region.xdb';
    private $localPath;
    public function __construct($localPath = null)
    {
        $this->localPath = $localPath ?? __DIR__ . '/../../data/ip2region.xdb';
    }
    public function update()
    {
        $backupPath = $this->localPath . '.backup';
        try {
            // 备份旧数据库
            if (file_exists($this->localPath)) {
                copy($this->localPath, $backupPath);
            }
            // 下载新数据库
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $this->downloadUrl,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 60,
                CURLOPT_FOLLOWLOCATION => true
            ]);
            $data = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            if ($httpCode === 200 && strlen($data) > 1000) {
                file_put_contents($this->localPath, $data);
                echo "IP数据库更新成功\n";
                return true;
            } else {
                throw new \Exception("下载失败: HTTP {$httpCode}");
            }
        } catch (\Exception $e) {
            // 恢复备份
            if (file_exists($backupPath)) {
                copy($backupPath, $this->localPath);
                unlink($backupPath);
            }
            echo "更新失败: " . $e->getMessage() . "\n";
            return false;
        }
        // 删除备份
        if (file_exists($backupPath)) {
            unlink($backupPath);
        }
    }
}

风控系统模块

1 风控引擎类

<?php
namespace App\RiskEngine;
class RiskEngine
{
    private $redis;
    private $rules = [];
    private $score = 0;
    private $riskDetails = [];
    public function __construct($redis = null)
    {
        $this->redis = $redis ?? new \Redis();
        $this->loadDefaultRules();
    }
    /**
     * 加载默认规则
     */
    private function loadDefaultRules()
    {
        $this->rules = [
            'frequency' => [
                'enabled' => true,
                'limit' => 100, // 每分钟最大请求数
                'weight' => 30,  // 违规权重
                'time_window' => 60 // 时间窗口(秒)
            ],
            'geography' => [
                'enabled' => true,
                'black_countries' => ['KP', 'IR', 'SY'], // 高风险国家
                'high_risk_countries' => ['RU', 'CN', 'NG'],
                'weight' => 40
            ],
            'proxy' => [
                'enabled' => true,
                'weight' => 25
            ],
            'device_fingerprint' => [
                'enabled' => true,
                'max_devices_per_ip' => 5,
                'weight' => 20
            ],
            'behavior' => [
                'enabled' => true,
                'speed_limit' => 5, // 每秒操作数
                'weight' => 35
            ]
        ];
    }
    /**
     * 执行风控检查
     */
    public function evaluate($context)
    {
        $this->score = 0;
        $this->riskDetails = [];
        // 执行各规则检查
        $results = [
            $this->checkFrequency($context),
            $this->checkGeography($context),
            $this->checkProxy($context),
            $this->checkDeviceFingerprint($context),
            $this->checkBehavior($context)
        ];
        // 汇总结果
        foreach ($results as $result) {
            if ($result['risk']) {
                $this->score += $result['points'];
                $this->riskDetails[] = $result['detail'];
            }
        }
        return [
            'score' => $this->score,
            'level' => $this->getRiskLevel(),
            'details' => $this->riskDetails,
            'action' => $this->getAction()
        ];
    }
    /**
     * 检查访问频率
     */
    private function checkFrequency($context)
    {
        $rule = $this->rules['frequency'];
        if (!$rule['enabled']) {
            return ['risk' => false, 'points' => 0, 'detail' => ''];
        }
        $ip = $context['ip'];
        $key = "risk:frequency:{$ip}";
        $current = $this->redis->incr($key);
        if ($current === 1) {
            $this->redis->expire($key, $rule['time_window']);
        }
        if ($current > $rule['limit']) {
            return [
                'risk' => true,
                'points' => $rule['weight'],
                'detail' => "访问频率过高: {$current}/{$rule['limit']}"
            ];
        }
        return ['risk' => false, 'points' => 0, 'detail' => ''];
    }
    /**
     * 检查地理位置风险
     */
    private function checkGeography($context)
    {
        $rule = $this->rules['geography'];
        if (!$rule['enabled'] || empty($context['country_code'])) {
            return ['risk' => false, 'points' => 0, 'detail' => ''];
        }
        $countryCode = strtoupper($context['country_code']);
        if (in_array($countryCode, $rule['black_countries'])) {
            return [
                'risk' => true,
                'points' => 100,
                'detail' => "高风险国家: {$countryCode}"
            ];
        }
        if (in_array($countryCode, $rule['high_risk_countries'])) {
            return [
                'risk' => true,
                'points' => $rule['weight'],
                'detail' => "中风险国家: {$countryCode}"
            ];
        }
        return ['risk' => false, 'points' => 0, 'detail' => ''];
    }
    /**
     * 检查代理/VPN
     */
    private function checkProxy($context)
    {
        $rule = $this->rules['proxy'];
        if (!$rule['enabled']) {
            return ['risk' => false, 'points' => 0, 'detail' => ''];
        }
        $isProxy = false;
        $proxyType = '';
        // 检查常见的代理标识
        if (!empty($context['headers'])) {
            $headers = $context['headers'];
            // 检查常见的代理头部
            $proxyHeaders = [
                'HTTP_VIA',
                'HTTP_X_FORWARDED_FOR',
                'HTTP_X_FORWARDED',
                'HTTP_FORWARDED',
                'HTTP_X_FORWARDED_HOST',
                'HTTP_X_PROXY_ID',
                'HTTP_PROXY_CONNECTION'
            ];
            foreach ($proxyHeaders as $header) {
                if (!empty($headers[$header])) {
                    $isProxy = true;
                    $proxyType = $header;
                    break;
                }
            }
        }
        // 检查代理IP数据库
        if (!$isProxy && !empty($context['ip'])) {
            $proxyIpKey = "proxy_ips:{$context['ip']}";
            $isProxy = $this->redis->sIsMember('known_proxy_ips', $context['ip']);
        }
        if ($isProxy) {
            return [
                'risk' => true,
                'points' => $rule['weight'],
                'detail' => "检测到代理/VPN: {$proxyType}"
            ];
        }
        return ['risk' => false, 'points' => 0, 'detail' => ''];
    }
    /**
     * 检查设备指纹
     */
    private function checkDeviceFingerprint($context)
    {
        $rule = $this->rules['device_fingerprint'];
        if (!$rule['enabled'] || empty($context['device_id'])) {
            return ['risk' => false, 'points' => 0, 'detail' => ''];
        }
        $ip = $context['ip'];
        $deviceId = $context['device_id'];
        $key = "risk:devices:{$ip}";
        // 记录设备关联
        $this->redis->sAdd($key, $deviceId);
        $this->redis->expire($key, 86400); // 24小时
        $deviceCount = $this->redis->sCard($key);
        if ($deviceCount > $rule['max_devices_per_ip']) {
            return [
                'risk' => true,
                'points' => $rule['weight'],
                'detail' => "设备数量异常: {$deviceCount}/{$rule['max_devices_per_ip']}"
            ];
        }
        return ['risk' => false, 'points' => 0, 'detail' => ''];
    }
    /**
     * 检查行为模式
     */
    private function checkBehavior($context)
    {
        $rule = $this->rules['behavior'];
        if (!$rule['enabled']) {
            return ['risk' => false, 'points' => 0, 'detail' => ''];
        }
        $userId = $context['user_id'] ?? 'anonymous';
        $action = $context['action'] ?? 'unknown';
        $key = "risk:behavior:{$userId}:{$action}";
        // 记录操作时间戳
        $now = microtime(true);
        $this->redis->zAdd($key, $now, $now . ':' . uniqid());
        $this->redis->expire($key, 10); // 10秒窗口
        // 清除过期数据
        $this->redis->zRemRangeByScore($key, 0, $now - 10);
        // 计算操作速度
        $count = $this->redis->zCard($key);
        if ($count > $rule['speed_limit']) {
            return [
                'risk' => true,
                'points' => $rule['weight'],
                'detail' => "操作速度异常: {$count}/{$rule['speed_limit']}"
            ];
        }
        return ['risk' => false, 'points' => 0, 'detail' => ''];
    }
    /**
     * 获取风险等级
     */
    private function getRiskLevel()
    {
        if ($this->score >= 100) return 'critical';
        if ($this->score >= 70) return 'high';
        if ($this->score >= 40) return 'medium';
        if ($this->score >= 20) return 'low';
        return 'safe';
    }
    /**
     * 获取建议操作
     */
    private function getAction()
    {
        switch ($this->getRiskLevel()) {
            case 'critical':
                return 'block';
            case 'high':
                return 'challenge_captcha';
            case 'medium':
                return 'require_verification';
            case 'low':
                return 'monitor';
            default:
                return 'allow';
        }
    }
    /**
     * 封禁IP
     */
    public function blockIp($ip, $minutes = 60)
    {
        $key = "blocked_ips:{$ip}";
        $this->redis->setEx($key, $minutes * 60, '1');
    }
    /**
     * 检查IP是否被封禁
     */
    public function isIpBlocked($ip)
    {
        return $this->redis->exists("blocked_ips:{$ip}");
    }
    /**
     * 获取风控详情
     */
    public function getRiskDetails()
    {
        return $this->riskDetails;
    }
}

2 风控中间件

<?php
namespace App\Http\Middleware;
use App\RiskEngine\RiskEngine;
use App\Utils\IpLocation;
use Closure;
class RiskControlMiddleware
{
    private $riskEngine;
    private $ipLocation;
    public function __construct(RiskEngine $riskEngine, IpLocation $ipLocation)
    {
        $this->riskEngine = $riskEngine;
        $this->ipLocation = $ipLocation;
    }
    public function handle($request, Closure $next)
    {
        $ip = $this->ipLocation->getClientIp();
        // 检查IP是否被封禁
        if ($this->riskEngine->isIpBlocked($ip)) {
            return response()->json([
                'code' => 403,
                'message' => '访问被限制'
            ], 403);
        }
        // 获取地理位置信息
        $location = $this->ipLocation->getLocation($ip);
        // 构建风控上下文
        $context = [
            'ip' => $ip,
            'user_id' => auth()->id(),
            'device_id' => $request->header('X-Device-ID'),
            'user_agent' => $request->userAgent(),
            'headers' => $request->headers->all(),
            'action' => $request->route()->getName() ?? 'unknown',
            'country_code' => $location['country_code'] ?? '',
            'request_params' => $request->all()
        ];
        // 执行风控检查
        $result = $this->riskEngine->evaluate($context);
        // 根据风控结果执行操作
        switch ($result['action']) {
            case 'block':
                $this->riskEngine->blockIp($ip, 30);
                return response()->json([
                    'code' => 403,
                    'message' => '访问被限制',
                    'risk_score' => $result['score']
                ], 403);
            case 'challenge_captcha':
                return response()->json([
                    'code' => 401,
                    'message' => '需要验证',
                    'captcha_required' => true,
                    'risk_score' => $result['score']
                ], 401);
            case 'require_verification':
                // 记录风险日志
                $this->logRiskEvent($ip, $result);
                break;
            case 'monitor':
                // 仅记录日志
                $this->logRiskEvent($ip, $result, 'info');
                break;
        }
        return $next($request);
    }
    private function logRiskEvent($ip, $result, $level = 'warning')
    {
        // 记录风控日志到数据库或日志文件
        \Log::channel('risk')->log($level, "Risk event detected", [
            'ip' => $ip,
            'score' => $result['score'],
            'level' => $result['level'],
            'details' => $result['details'],
            'timestamp' => now()
        ]);
    }
}

3 风控记录模型

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class RiskRecord extends Model
{
    protected $table = 'risk_records';
    protected $fillable = [
        'ip',
        'user_id',
        'risk_score',
        'risk_level',
        'action_taken',
        'details',
        'user_agent',
        'request_url',
        'request_method'
    ];
    protected $casts = [
        'details' => 'array',
        'created_at' => 'datetime'
    ];
    /**
     * 获取某个IP的风险统计
     */
    public static function getIpRiskStats($ip, $days = 7)
    {
        return self::where('ip', $ip)
            ->where('created_at', '>=', now()->subDays($days))
            ->selectRaw('
                COUNT(*) as total_events,
                AVG(risk_score) as avg_score,
                MAX(risk_score) as max_score,
                COUNT(CASE WHEN risk_level = "critical" THEN 1 END) as critical_count,
                COUNT(CASE WHEN risk_level = "high" THEN 1 END) as high_count
            ')
            ->first();
    }
    /**
     * 获取高风险IP列表
     */
    public static function getHighRiskIps($threshold = 70, $limit = 100)
    {
        return self::where('risk_score', '>=', $threshold)
            ->where('created_at', '>=', now()->subHours(24))
            ->groupBy('ip')
            ->selectRaw('ip, COUNT(*) as event_count, AVG(risk_score) as avg_score')
            ->orderByDesc('avg_score')
            ->limit($limit)
            ->get();
    }
}

4 风控统计服务

<?php
namespace App\Services;
use App\Models\RiskRecord;
use Illuminate\Support\Facades\Redis;
class RiskStatisticsService
{
    /**
     * 获取实时风控仪表盘数据
     */
    public function getDashboardData()
    {
        return [
            'total_requests_today' => $this->getTodayTotalRequests(),
            'blocked_ips_count' => $this->getBlockedIpsCount(),
            'high_risk_events' => $this->getHighRiskEventsCount(),
            'current_risk_level' => $this->getCurrentRiskLevel(),
            'top_risk_ips' => $this->getTopRiskIps(),
            'risk_trend' => $this->getRiskTrend()
        ];
    }
    /**
     * 获取今天的总请求数
     */
    private function getTodayTotalRequests()
    {
        $key = 'stats:requests:' . date('Y-m-d');
        return Redis::get($key) ?? 0;
    }
    /**
     * 获取被封禁的IP数量
     */
    private function getBlockedIpsCount()
    {
        // 使用Redis记录被封禁IP
        $keys = Redis::keys('blocked_ips:*');
        return count($keys);
    }
    /**
     * 获取高风险事件数量
     */
    private function getHighRiskEventsCount()
    {
        return RiskRecord::where('risk_level', 'high')
            ->where('created_at', '>=', now()->subHours(24))
            ->count();
    }
    /**
     * 获取当前风险等级
     */
    private function getCurrentRiskLevel()
    {
        $highRiskCount = $this->getHighRiskEventsCount();
        if ($highRiskCount > 1000) return 'critical';
        if ($highRiskCount > 500) return 'high';
        if ($highRiskCount > 100) return 'medium';
        return 'low';
    }
    /**
     * 获取风险最高的IP
     */
    private function getTopRiskIps($limit = 10)
    {
        return RiskRecord::selectRaw('ip, COUNT(*) as count, AVG(risk_score) as avg_score')
            ->where('created_at', '>=', now()->subHours(24))
            ->groupBy('ip')
            ->orderByDesc('avg_score')
            ->limit($limit)
            ->get();
    }
    /**
     * 获取风险趋势
     */
    private function getRiskTrend()
    {
        $trend = [];
        for ($i = 6; $i >= 0; $i--) {
            $date = now()->subHours($i * 4);
            $count = RiskRecord::where('created_at', '>=', $date)
                ->where('created_at', '<', $date->copy()->addHours(4))
                ->count();
            $trend[] = [
                'time' => $date->format('H:i'),
                'count' => $count
            ];
        }
        return $trend;
    }
}

数据库迁移文件

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRiskTables extends Migration
{
    public function up()
    {
        // 风险记录表
        Schema::create('risk_records', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('ip', 45)->index();
            $table->unsignedBigInteger('user_id')->nullable()->index();
            $table->integer('risk_score')->default(0);
            $table->string('risk_level', 20)->default('safe');
            $table->string('action_taken', 50)->nullable();
            $table->json('details')->nullable();
            $table->string('user_agent', 500)->nullable();
            $table->string('request_url', 500)->nullable();
            $table->string('request_method', 10)->nullable();
            $table->timestamps();
            $table->index(['ip', 'created_at']);
            $table->index(['risk_level', 'created_at']);
        });
        // IP黑名单表
        Schema::create('ip_blacklist', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('ip', 45)->unique();
            $table->string('reason', 500)->nullable();
            $table->timestamp('blocked_until')->nullable();
            $table->unsignedBigInteger('blocked_by')->nullable();
            $table->timestamps();
            $table->index('blocked_until');
        });
        // IP白名单表
        Schema::create('ip_whitelist', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('ip', 45)->unique();
            $table->string('description', 500)->nullable();
            $table->timestamps();
        });
        // 风险规则配置表
        Schema::create('risk_rules', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name', 100)->unique();
            $table->string('description', 500)->nullable();
            $table->json('config')->nullable();
            $table->boolean('enabled')->default(true);
            $table->integer('priority')->default(0);
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('risk_records');
        Schema::dropIfExists('ip_blacklist');
        Schema::dropIfExists('ip_whitelist');
        Schema::dropIfExists('risk_rules');
    }
}

使用示例

1 在控制器中使用

<?php
namespace App\Http\Controllers;
use App\RiskEngine\RiskEngine;
use App\Utils\IpLocation;
use Illuminate\Http\Request;
class ExampleController extends Controller
{
    private $riskEngine;
    private $ipLocation;
    public function __construct(RiskEngine $riskEngine, IpLocation $ipLocation)
    {
        $this->riskEngine = $riskEngine;
        $this->ipLocation = $ipLocation;
    }
    public function login(Request $request)
    {
        $ip = $this->ipLocation->getClientIp();
        $location = $this->ipLocation->getLocation($ip);
        // 创建风控上下文
        $context = [
            'ip' => $ip,
            'user_id' => $request->input('user_id'),
            'device_id' => $request->header('X-Device-ID'),
            'user_agent' => $request->userAgent(),
            'action' => 'login',
            'country_code' => $location['country_code'] ?? '',
        ];
        // 执行风控检查
        $result = $this->riskEngine->evaluate($context);
        if ($result['action'] === 'block') {
            $this->riskEngine->blockIp($ip, 60);
            return response()->json([
                'message' => '登录失败,请稍后重试',
                'risk_score' => $result['score']
            ], 403);
        }
        if ($result['action'] === 'challenge_captcha') {
            return response()->json([
                'message' => '需要验证码验证',
                'captcha_required' => true
            ], 401);
        }
        // 正常登录流程
        // ...
    }
}

2 配置文件

<?php
// config/risk.php
return [
    'enabled' => env('RISK_CONTROL_ENABLED', true),
    'redis' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_DB', 0),
    ],
    'ip_database' => [
        'path' => storage_path('app/ip2region.xdb'),
        'auto_update' => false,
        'update_interval' => 7, // 天
    ],
    'rules' => [
        'frequency' => [
            'enabled' => true,
            'limit' => 100,
            'time_window' => 60,
            'weight' => 30,
        ],
        'geography' => [
            'enabled' => true,
            'black_countries' => ['KP', 'IR', 'SY'],
            'high_risk_countries' => ['RU', 'CN', 'NG'],
            'weight' => 40,
        ],
        'proxy' => [
            'enabled' => true,
            'weight' => 25,
        ],
        'device_fingerprint' => [
            'enabled' => true,
            'max_devices_per_ip' => 5,
            'weight' => 20,
        ],
        'behavior' => [
            'enabled' => true,
            'speed_limit' => 5,
            'weight' => 35,
        ],
    ],
    'actions' => [
        'block' => [
            'duration' => 30, // 分钟
            'response_code' => 403,
        ],
        'challenge_captcha' => [
            'response_code' => 401,
        ],
    ],
    'logging' => [
        'channel' => 'risk',
        'level' => 'warning',
    ],
];

这个实现包含:

  1. IP归属查询:支持离线数据库和在线API
  2. 风控引擎:多维度风险评估
  3. 访问频率控制:基于Redis的计数器
  4. 地理位置风控:国家/地区黑白名单
  5. 代理检测:识别代理/VPN流量
  6. 设备指纹:设备关联分析
  7. 行为分析:操作速度检测
  8. 完整的中间件:自动执行风控检查
  9. 统计和监控:风控数据可视化支持

系统会根据风险评分自动采取相应措施,如封禁、验证码验证、监控等。

抱歉,评论功能暂时关闭!