php项目统计关门防守成功几次?

wen PHP项目 5

本文目录导读:

php项目统计关门防守成功几次?

  1. 方案一:基于中间件/拦截器的统计(推荐)
  2. 方案二:基于业务逻辑的统计(登录/API调用)
  3. 方案三:通用文件/数据库日志统计(简单项目)
  4. 方案四:实时仪表板(使用Redis统计)
  5. 重要提示

在PHP项目中,要统计“关门防守成功”的次数,通常指的是阻止特定攻击(如SQL注入、XSS、暴力破解等)限制非法访问的次数,具体实现取决于你的“防守”逻辑是什么。

以下是几种常见场景的统计实现方案:

基于中间件/拦截器的统计(推荐)

如果你使用 LaravelSymfonyThinkPHP,最好的方式是在全局中间件中统计。

创建日志/统计表

CREATE TABLE defense_logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    type VARCHAR(50) NOT NULL COMMENT '防守类型: sql_injection, brute_force, rate_limit',
    ip_address VARCHAR(45) NOT NULL,
    count INT DEFAULT 0,
    last_attempt_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_type_ip (type, ip_address)
);

中间件逻辑(Laravel示例)

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\DB;
class SecurityMiddleware
{
    public function handle($request, Closure $next)
    {
        // --- 防守检测逻辑 ---
        $blocked = false;
        $type = 'unknown';
        // 示例1:检测SQL注入(简单正则)
        if (preg_match('/\b(SELECT|UNION|INSERT|DELETE)\b/i', $request->getQueryString() ?? '')) {
            $blocked = true;
            $type = 'sql_injection';
        }
        // 示例2:频率限制(防暴力破解)
        $ip = $request->ip();
        $key = 'login_attempts_' . $ip;
        if (cache($key, 0) >= 5) {
            $blocked = true;
            $type = 'brute_force';
        }
        // --- 如果触发了防守,则记录 ---
        if ($blocked) {
            // 原子更新统计(防止并发冲突)
            DB::table('defense_logs')
                ->updateOrInsert(
                    ['type' => $type, 'ip_address' => $ip],
                    ['last_attempt_at' => now()]
                );
            // 或者使用 Redis 计数器
            Redis::incr("defense:{$type}:{$ip}");
            // 返回阻断响应
            return response('Forbidden', 403);
        }
        return $next($request);
    }
}

基于业务逻辑的统计(登录/API调用)

如果你的“关门”特指限制某用户登录失败API请求超限

<?php
class LoginService
{
    private $redis;
    private $maxAttempts = 5; // 最多尝试次数
    public function __construct(\Redis $redis)
    {
        $this->redis = $redis;
    }
    public function attemptLogin($username, $password)
    {
        $key = "login_lock:{$username}";
        // 1. 检查是否已被锁住
        if ($this->redis->get($key) >= $this->maxAttempts) {
            // 统计防守成功次数(自增)
            $this->redis->incr("defense_count:login_lock");
            return ['success' => false, 'msg' => '账户已被锁定,请稍后再试'];
        }
        // 2. 模拟验证登陆
        if ($this->validateUser($username, $password)) {
            $this->redis->del($key);
            return ['success' => true];
        } else {
            // 登录失败,增加尝试次数
            $attempts = $this->redis->incr($key);
            // 如果达到阈值,记录防守成功
            if ($attempts == $this->maxAttempts) {
                $this->redis->incr("defense_count:login_lock");
            }
            return ['success' => false, 'msg' => '账号或密码错误'];
        }
    }
    public function getTotalDefenseCount()
    {
        return (int)$this->redis->get("defense_count:login_lock") ?: 0;
    }
}

通用文件/数据库日志统计(简单项目)

如果不依赖框架,可以用文件记录所有拦截日志,然后用PHP脚本汇总。

写入日志:

<?php
function logDefenseEvent($type, $ip) {
    $logFile = __DIR__ . '/defense.log'; // 格式: '2024-01-01 12:00:00|sql_injection|192.168.1.1'
    $line = date('Y-m-d H:i:s') . "|{$type}|{$ip}\n";
    file_put_contents($logFile, $line, FILE_APPEND);
}
// 在防守触发处调用
if (isset($_GET['id']) && preg_match('/^[0-9]+$/', $_GET['id']) === 0) {
    logDefenseEvent('sql_injection', $_SERVER['REMOTE_ADDR']);
    // 拦截处理...
    die('非法参数');
}

统计输出:

<?php
function getDefenseStats() {
    $stats = [];
    $lines = file(__DIR__ . '/defense.log', FILE_IGNORE_NEW_LINES);
    foreach ($lines as $line) {
        $parts = explode('|', $line);
        if (count($parts) === 3) {
            $type = $parts[1];
            $stats[$type] = ($stats[$type] ?? 0) + 1;
        }
    }
    return $stats;
}
// 查看统计
print_r(getDefenseStats()); 
// 输出: ['sql_injection' => 10, 'brute_force' => 3]

实时仪表板(使用Redis统计)

适合需要实时展示的场景:

<?php
// 防守成功时(Redis计数器)
$redis->incr("defense_total");  // 总次数
$redis->incr("defense_today:" . date('Y-m-d')); // 今日次数
$redis->incr("defense_type:{$type}"); // 按类型统计
// 查询统计
$total = $redis->get("defense_total") ?: 0;
$today = $redis->get("defense_today:" . date('Y-m-d')) ?: 0;
$sqlInjection = $redis->get("defense_type:sql_injection") ?: 0;

重要提示

  1. 并发问题:使用数据库或Redis的 INCR 原子操作,避免 SELECT→UPDATE 造成的计数丢失。
  2. 不记录攻击者:如果想记录攻击者IP,可以增加字段。
  3. 区分类型:建议统计时区分 sql注入XSS暴力破解 等不同防御类型。

如果你能告诉我具体是哪种“防守”(比如是防火墙、验证码、防刷还是登录限制),我可以给出更精确的代码。

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