PHP项目反欺诈与黑名单

wen PHP项目 1

本文目录导读:

PHP项目反欺诈与黑名单

  1. 核心数据表设计
  2. 核心反欺诈类
  3. 请求上下文类
  4. 风险结果类
  5. 中间件使用示例
  6. 自动清理脚本
  7. 配置建议

针对PHP项目的反欺诈与黑名单机制,我为您提供一个完整的实现方案,这个系统包含IP、设备、用户等多维度检测。

核心数据表设计

-- 黑名单表
CREATE TABLE blacklist (
    id INT AUTO_INCREMENT PRIMARY KEY,
    type ENUM('ip', 'user_id', 'device_id', 'phone', 'email', 'card') NOT NULL,
    value VARCHAR(255) NOT NULL,
    reason VARCHAR(500),
    level TINYINT DEFAULT 1, -- 1-5, 5为最高风险
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expires_at TIMESTAMP NULL,
    status TINYINT DEFAULT 1, -- 1有效, 0禁用
    UNIQUE KEY uk_type_value (type, value),
    INDEX idx_type_status (type, status),
    INDEX idx_value (value),
    INDEX idx_expires (expires_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 行为日志表
CREATE TABLE behavior_log (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    ip VARCHAR(45),
    device_fingerprint VARCHAR(255),
    action VARCHAR(100),
    action_params TEXT,
    risk_score DECIMAL(5,2) DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_action (user_id, action),
    INDEX idx_ip (ip),
    INDEX idx_device (device_fingerprint),
    INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 风控规则表
CREATE TABLE risk_rules (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100),
    rule_type VARCHAR(50),
    conditions JSON, -- 规则条件
    action VARCHAR(50), -- deny, review, allow
    weight DECIMAL(5,2) DEFAULT 1,
    status TINYINT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

核心反欺诈类

<?php
namespace App\Security;
class AntiFraudManager
{
    private $db;
    private $cache;
    private $config;
    public function __construct(\PDO $db, $cache = null, array $config = [])
    {
        $this->db = $db;
        $this->cache = $cache;
        $this->config = array_merge([
            'max_login_attempts' => 5,
            'login_window' => 300,
            'max_register_per_ip' => 3,
            'register_window' => 3600,
            'risk_threshold' => 0.7
        ], $config);
    }
    /**
     * 检查请求是否安全
     */
    public function checkRequest(RequestContext $context): RiskResult
    {
        $totalRisk = 0;
        $reasons = [];
        // 1. 黑名单检查
        $blacklistCheck = $this->checkBlacklist($context);
        if ($blacklistCheck->isBlocked()) {
            return new RiskResult(true, $blacklistCheck->getReasons(), 1.0);
        }
        // 2. 行为分析
        $behaviorRisk = $this->analyzeBehavior($context);
        $totalRisk += $behaviorRisk['score'];
        $reasons = array_merge($reasons, $behaviorRisk['reasons']);
        // 3. 设备指纹检查
        $deviceRisk = $this->analyzeDevice($context);
        $totalRisk += $deviceRisk['score'];
        $reasons = array_merge($reasons, $deviceRisk['reasons']);
        // 4. 规则引擎
        $ruleResults = $this->applyRules($context);
        $totalRisk += $ruleResults['score'];
        $reasons = array_merge($reasons, $ruleResults['reasons']);
        $finalRisk = min($totalRisk, 1.0);
        $isBlocked = $finalRisk >= $this->config['risk_threshold'];
        // 记录行为日志
        $this->logBehavior($context, $finalRisk);
        return new RiskResult($isBlocked, $reasons, $finalRisk);
    }
    /**
     * 黑名单检查
     */
    private function checkBlacklist(RequestContext $context): RiskResult
    {
        $checks = [
            ['type' => 'ip', 'value' => $context->ip],
            ['type' => 'user_id', 'value' => $context->userId],
            ['type' => 'device_id', 'value' => $context->deviceId],
            ['type' => 'phone', 'value' => $context->phone],
            ['type' => 'email', 'value' => $context->email]
        ];
        $reasons = [];
        foreach ($checks as $check) {
            if (empty($check['value'])) continue;
            $stmt = $this->db->prepare(
                "SELECT reason, level FROM blacklist 
                 WHERE type = ? AND value = ? AND status = 1 
                 AND (expires_at IS NULL OR expires_at > NOW())"
            );
            $stmt->execute([$check['type'], $check['value']]);
            if ($row = $stmt->fetch()) {
                $reasons[] = "Blacklisted {$check['type']}: {$row['reason']}";
                return new RiskResult(true, $reasons, $row['level'] / 5);
            }
        }
        return new RiskResult(false, [], 0);
    }
    /**
     * 行为分析
     */
    private function analyzeBehavior(RequestContext $context): array
    {
        $score = 0;
        $reasons = [];
        // 检查登录频率
        if ($context->action === 'login') {
            $attempts = $this->getLoginAttempts($context->ip, $this->config['login_window']);
            if ($attempts >= $this->config['max_login_attempts']) {
                $score += 0.4;
                $reasons[] = "Excessive login attempts: {$attempts}";
            }
        }
        // 检查注册频率
        if ($context->action === 'register') {
            $registrations = $this->getRegistrationsByIP($context->ip, $this->config['register_window']);
            if ($registrations >= $this->config['max_register_per_ip']) {
                $score += 0.5;
                $reasons[] = "Excessive registrations from same IP";
            }
        }
        // 检查异常时间段
        $hour = date('H');
        if ($hour >= 1 && $hour <= 5) {
            $score += 0.1;
        }
        return ['score' => min($score, 1.0), 'reasons' => $reasons];
    }
    /**
     * 设备分析
     */
    private function analyzeDevice(RequestContext $context): array
    {
        $score = 0;
        $reasons = [];
        if (empty($context->deviceFingerprint)) {
            return ['score' => 0.1, 'reasons' => ['No device fingerprint']];
        }
        // 检查设备关联风险用户
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) as cnt FROM behavior_log 
             WHERE device_fingerprint = ? 
             AND risk_score > 0.5 
             AND created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)"
        );
        $stmt->execute([$context->deviceFingerprint]);
        $result = $stmt->fetch();
        if ($result['cnt'] > 3) {
            $score += 0.3;
            $reasons[] = "Device associated with risk activities";
        }
        return ['score' => min($score, 1.0), 'reasons' => $reasons];
    }
    /**
     * 规则引擎
     */
    private function applyRules(RequestContext $context): array
    {
        $totalScore = 0;
        $reasons = [];
        $stmt = $this->db->query("SELECT * FROM risk_rules WHERE status = 1");
        $rules = $stmt->fetchAll();
        foreach ($rules as $rule) {
            $conditions = json_decode($rule['conditions'], true);
            $matched = $this->evaluateConditions($conditions, $context);
            if ($matched) {
                $totalScore += $rule['weight'] * 0.1;
                $reasons[] = "Rule matched: {$rule['name']}";
                if ($rule['action'] === 'deny') {
                    $totalScore = 1.0;
                    break;
                }
            }
        }
        return ['score' => min($totalScore, 1.0), 'reasons' => $reasons];
    }
    /**
     * 添加黑名单
     */
    public function addToBlacklist(string $type, string $value, string $reason, 
                                    int $level = 3, ?int $expiresInHours = null): bool
    {
        $expiresAt = $expiresInHours ? date('Y-m-d H:i:s', time() + $expiresInHours * 3600) : null;
        try {
            $stmt = $this->db->prepare(
                "INSERT INTO blacklist (type, value, reason, level, expires_at) 
                 VALUES (?, ?, ?, ?, ?) 
                 ON DUPLICATE KEY UPDATE reason = VALUES(reason), level = VALUES(level), 
                                          expires_at = VALUES(expires_at), status = 1"
            );
            return $stmt->execute([$type, $value, $reason, $level, $expiresAt]);
        } catch (\Exception $e) {
            // 记录日志
            return false;
        }
    }
    /**
     * 获取登录尝试次数
     */
    private function getLoginAttempts(string $ip, int $window): int
    {
        $key = "login_attempts:{$ip}";
        if ($this->cache) {
            return (int)$this->cache->get($key, 0);
        }
        $stmt = $this->db->prepare(
            "SELECT COUNT(*) FROM behavior_log 
             WHERE ip = ? AND action = 'login' 
             AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND)"
        );
        $stmt->execute([$ip, $window]);
        return (int)$stmt->fetchColumn();
    }
}

请求上下文类

<?php
namespace App\Security;
class RequestContext
{
    public $ip;
    public $userId;
    public $deviceId;
    public $deviceFingerprint;
    public $phone;
    public $email;
    public $action;
    public $userAgent;
    public $referer;
    public $timestamp;
    public function __construct(array $data = [])
    {
        $this->ip = $data['ip'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
        $this->userId = $data['user_id'] ?? null;
        $this->deviceId = $data['device_id'] ?? null;
        $this->deviceFingerprint = $data['fingerprint'] ?? '';
        $this->phone = $data['phone'] ?? '';
        $this->email = $data['email'] ?? '';
        $this->action = $data['action'] ?? '';
        $this->userAgent = $data['user_agent'] ?? $_SERVER['HTTP_USER_AGENT'] ?? '';
        $this->referer = $data['referer'] ?? $_SERVER['HTTP_REFERER'] ?? '';
        $this->timestamp = $data['timestamp'] ?? time();
    }
}

风险结果类

<?php
namespace App\Security;
class RiskResult
{
    private $isBlocked;
    private $reasons;
    private $riskScore;
    public function __construct(bool $isBlocked, array $reasons = [], float $riskScore = 0)
    {
        $this->isBlocked = $isBlocked;
        $this->reasons = $reasons;
        $this->riskScore = $riskScore;
    }
    public function isBlocked(): bool
    {
        return $this->isBlocked;
    }
    public function getReasons(): array
    {
        return $this->reasons;
    }
    public function getRiskScore(): float
    {
        return $this->riskScore;
    }
    public function getHttpCode(): int
    {
        return $this->isBlocked ? 403 : 200;
    }
    public function toArray(): array
    {
        return [
            'blocked' => $this->isBlocked,
            'risk_score' => $this->riskScore,
            'reasons' => $this->reasons
        ];
    }
}

中间件使用示例

<?php
namespace App\Middleware;
use App\Security\AntiFraudManager;
use App\Security\RequestContext;
class AntiFraudMiddleware
{
    private $fraudManager;
    public function __construct(AntiFraudManager $fraudManager)
    {
        $this->fraudManager = $fraudManager;
    }
    public function handle($request, $next)
    {
        // 创建请求上下文
        $context = new RequestContext([
            'action' => $request->getPath(),
            'user_id' => $request->getUserId(),
            'device_id' => $request->header('X-Device-ID'),
            'fingerprint' => $this->getDeviceFingerprint($request),
            'phone' => $request->input('phone'),
            'email' => $request->input('email')
        ]);
        // 风控检查
        $result = $this->fraudManager->checkRequest($context);
        if ($result->isBlocked()) {
            return response()->json([
                'error' => 'Request blocked',
                'reasons' => $result->getReasons(),
                'code' => $result->getHttpCode()
            ], $result->getHttpCode());
        }
        // 将风险信息注入请求
        $request->attributes->set('risk_score', $result->getRiskScore());
        return $next($request);
    }
    private function getDeviceFingerprint($request): string
    {
        // 使用多个参数生成设备指纹
        $components = [
            $request->header('User-Agent'),
            $request->header('Accept-Language'),
            $request->header('Accept-Encoding'),
            $request->ip()
        ];
        return md5(implode('|', $components));
    }
}

自动清理脚本

<?php
// cron_jobs/cleanup_blacklist.php
// 建议每天运行一次
$stmt = $db->prepare(
    "DELETE FROM blacklist WHERE expires_at IS NOT NULL AND expires_at < NOW()"
);
$stmt->execute();
// 清理过期行为日志(保留最近30天)
$stmt = $db->prepare(
    "DELETE FROM behavior_log WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)"
);
$stmt->execute();

配置建议

// config/antifraud.php
return [
    'redis' => [
        'host' => '127.0.0.1',
        'port' => 6379,
        'prefix' => 'antifraud:'
    ],
    'rate_limits' => [
        'login' => [
            'max_attempts' => 5,
            'window' => 300 // 5分钟
        ],
        'register' => [
            'max_attempts' => 3,
            'window' => 3600 // 1小时
        ],
        'api' => [
            'max_requests' => 100,
            'window' => 60 // 1分钟
        ]
    ],
    'blacklist' => [
        'auto_ban_threshold' => 0.8, // 触发自动加入黑名单的风险分数
        'auto_ban_duration' => 24  // 自动封禁小时数
    ],
    'notifications' => [
        'high_risk_alert' => true,
        'alert_channels' => ['email', 'sms'],
        'alert_recipients' => ['admin@example.com']
    ]
];

这个系统提供了完整的反欺诈功能,包括:

  • 多维黑名单:支持IP、用户、设备、手机、邮箱等多个维度
  • 行为分析:检测异常登录、注册频率等
  • 设备指纹:识别设备关联风险
  • 规则引擎:可配置的风控规则
  • 自动封禁:达到风险阈值自动加入黑名单
  • 缓存优化:支持Redis缓存提高性能
  • 可扩展性:易于添加新的检测规则

建议配合Nginx限流、验证码、实名认证等机制一起使用,构建完整的防护体系。

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