news 2026/9/16 14:06:01

PHP原生CC防护系统:请求指纹+动态限流+验证码闭环

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PHP原生CC防护系统:请求指纹+动态限流+验证码闭环

简介:这是一套面向PHP开发者与Web安全初学者的轻量级CC攻击防护实践源码,聚焦于解决PHP网站在高并发场景下易遭模拟请求式DDoS(即CC攻击)导致服务瘫痪的问题。资源共14个文件,含7个核心PHP脚本(如anti_ddos.php、securitecode.php、Verify_your_identity.php等,分别承担请求限频、验证码校验、身份验证与黑名单拦截功能)、6个说明类TXT文档(含部署配置与使用教程)、1个CSS样式文件(用于验证页面UI),整体仅39KB,便于快速集成与二次开发。目前已有167人学习下载,适合中小型PHP站点快速部署基础层防护,或作为Web安全课程中“应用层攻击防御”模块的教学案例。读者可直接复用其IP频率控制逻辑、多级验证流程设计及异常行为识别思路,并结合config.php灵活调整阈值参数,深入理解从流量监控到响应拦截的完整防护链路。

1. 这不是WAF,而是一套可嵌入、可调试、可审计的PHP层CC防御逻辑链

你刚上线一个用ThinkPHP写的会员系统,凌晨三点收到告警:首页QPS从80飙到2400,但真实用户数为0;Nginx access.log里全是/login.php?username=test&password=123的重复GET请求,User-Agent却写着“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36”,和你昨天测试时一模一样——这不是流量突增,是有人在用Python脚本轮询撞库。此时打开宝塔面板看PHP进程,php-fpm子进程占满CPU,但netstat -an | grep :80显示连接数并不高。传统CDN或云WAF对这种应用层慢速攻击响应滞后,而你手头只有FTP权限和一个能改index.php的后台。这套“简洁实用的PHP防被CC攻击网站系统源码”就是为这种场景设计的:它不依赖外部服务,不修改PHP核心配置,仅靠include一行就能接入任意PHP站点,所有防护逻辑运行在$_SERVER['REQUEST_TIME_FLOAT']精度下,用file_put_contents()写日志、用session_start()做状态跟踪、用imagepng()动态生成验证码——它不是黑盒中间件,而是你能逐行var_dump()、加断点、改阈值、导出日志的防御代码。

它解决的是「合法请求洪流」场景下的资源耗尽问题:当攻击者用100个IP每秒各发5次搜索请求,总QPS才500,远低于服务器承载上限,但每个请求都触发完整MySQL查询+模板渲染,数据库连接池瞬间打满。这类攻击绕过基于IP频次的Nginx限流(因IP分散),也骗过基于User-Agent的简单过滤(因UA伪造得像真浏览器)。本源码通过三重校验闭环应对:首次访问放行但埋securitecode.php种子;二次高频请求触发Verify_your_identity.php弹验证码;三次失败则写入config.php维护的内存级黑名单。整个流程不依赖Redis或Memcached,纯PHP原生函数实现,连gd扩展都做了降级兼容——哪怕你的虚拟主机禁用了imagettftext(),它也能回退到字符拼接式验证码。

适合两类人:一是运维能力有限但需快速止血的中小站点开发者,你只需把anti_ddos.php放在入口文件顶部,调整config.php里的$max_requests_per_minute = 30;即可生效;二是安全研究者,源码中core2.php封装了请求指纹生成算法(md5($_SERVER['HTTP_USER_AGENT'].substr($_SERVER['REMOTE_ADDR'],0,7).$_SERVER['REQUEST_URI'])),start.php展示了如何用register_shutdown_function()捕获超时请求,这些细节在商业WAF文档里从不会公开。

2. 请求指纹建模与动态阈值控制:为什么单纯IP限流在CC攻击中失效

2.1 CC攻击的本质是“合法行为”的规模化滥用

传统DDoS攻击靠UDP洪水或SYN泛洪消耗带宽和连接数,而CC攻击(Challenge Collapsar)专攻应用层。它不追求高并发连接,而是模拟人类操作节奏:比如每3秒发起一次商品详情页请求,每次携带不同utm_source参数,User-Agent轮换Chrome/Firefox/Safari,甚至加入随机Referer。Nginx的limit_req zone=cc burst=5 nodelay;对此类攻击效果极差——因为burst值设小了误杀正常用户(如手机端加载图片+JS+CSS共4次请求),设大了形同虚设(攻击者开10个线程,每个线程每分钟发60次请求,总QPS才10,远低于阈值)。本源码放弃IP维度单一限流,转而构建多维请求指纹,核心逻辑在core2.php第42行:

function generate_request_fingerprint() { $ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'; $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?: '/'; $query = $_SERVER['QUERY_STRING'] ?? ''; // 关键:剔除会频繁变动的参数,保留业务关键路径 $clean_query = preg_replace('/(utm_[^&=]+|_t=[^&=]+)/', '', $query); $fingerprint = md5($ua . substr($ip, 0, 7) . $uri . $clean_query); return $fingerprint; }

提示substr($ip, 0, 7)取IP前7位而非全量,是为了应对同一局域网用户(如公司WiFi)被误判。若你的站点主要面向国内移动用户,建议改为substr($ip, 0, 3)匹配C类网段,减少指纹碰撞。

该指纹将“同一用户在相同UA下访问相同路径”映射为唯一字符串,比单纯IP更精准。例如攻击脚本用100个代理IP刷/product?id=123,但UA固定为curl/7.68.0,指纹全部相同,触发统一限流;而真实用户用不同手机访问/product?id=123&utm_source=wechat/product?id=123&utm_source=qq,因clean_query剔除utm参数,指纹仍一致,避免误伤。

2.2 动态滑动窗口计数器的PHP原生实现

anti_ddos.php第68行调用check_request_rate()函数,其内部使用file_get_contents()读取./logs/rate_limit.log(非数据库!),按指纹分组统计最近60秒请求数。关键在于它不依赖redis INCR,而是用PHP数组+文件锁实现原子计数:

function check_request_rate($fingerprint, $max_requests = 30, $window_seconds = 60) { $log_file = './logs/rate_limit.log'; $now = time(); $cutoff = $now - $window_seconds; // 1. 读取并清理过期记录 $records = []; if (file_exists($log_file)) { $content = file_get_contents($log_file); $lines = explode("\n", trim($content)); foreach ($lines as $line) { if (empty($line)) continue; list($ts, $fp) = explode('|', $line, 2); if ((int)$ts >= $cutoff && $fp === $fingerprint) { $records[] = (int)$ts; } } } // 2. 写入当前请求时间戳 file_put_contents($log_file, "$now|$fingerprint\n", FILE_APPEND | LOCK_EX); // 3. 判断是否超限 return count($records) >= $max_requests; }

注意FILE_APPEND | LOCK_EX确保多进程写入不覆盖。但高并发下file_get_contents()可能读到部分写入的脏数据,因此实际生产环境建议将$window_seconds设为120秒,用时间换一致性。若需更高性能,可将此逻辑迁移到apcu_store(),但需确认服务器启用了APCu扩展。

该计数器与Nginx限流的根本区别在于:它感知的是“业务行为”而非“网络连接”。当/api/order/create接口被刷单攻击时,即使攻击者分散在1000个IP,只要UA和路径相同,所有请求共享同一个计数器,立即触发防护。而Nginx对每个IP单独计数,需配置limit_req_zone $binary_remote_addr配合limit_req指令,且无法识别UA伪装。

2.3 阈值参数的业务化调优方法

config.php中定义了三组可调参数,需根据业务特征调整:

参数名默认值调优依据典型场景示例
$max_requests_per_minute30单个用户每分钟合理操作次数电商站搜索页:设为15(用户很少1分钟搜15次);论坛发帖页:设为3(防灌水)
$captcha_trigger_count5触发验证码的连续请求数登录页:设为3(防爆破);静态文章页:设为20(防爬虫)
$blacklist_duration_minutes1440黑名单保留时长(分钟)临时攻击:设为60;已知恶意IP段:设为10080(7天)

调整后需验证效果:用ab -n 100 -c 10 http://yoursite.com/模拟并发,观察./logs/attack_log.txt中是否出现[BLOCKED] fingerprint=xxx ip=192.168.1.100。若正常用户被误拦,检查generate_request_fingerprint()是否误剔除了关键参数(如支付接口的order_id必须保留);若攻击未被拦截,增大$captcha_trigger_count并检查Verify_your_identity.php是否成功返回验证码图片(用浏览器直接访问该文件测试)。

3. 验证码挑战机制与人机识别闭环设计

3.1securitecode.php:无依赖的GD库降级方案

验证码是CC防护的关键闸门,但很多共享主机禁用imagettftext()(需指定字体文件路径)或imageantialias()securitecode.php采用三层降级策略:

  1. 首选方案:用imagecreatefrompng()加载预置的./assets/bg.png作为背景,imagestring()绘制字符(无需字体文件)
  2. 备选方案:若背景图不存在,用imagecreate(120,40)生成纯色背景,imagefilledrectangle()画底色
  3. 兜底方案:若GD扩展完全禁用,返回纯文本验证码($_SESSION['captcha_code']明文写入,前端用<span>显示)

核心代码在securitecode.php第89行:

// 尝试加载背景图 $bg_path = './assets/bg.png'; if (file_exists($bg_path) && function_exists('imagecreatefrompng')) { $im = imagecreatefrompng($bg_path); } else { // 创建纯色背景 $im = imagecreate(120, 40); $bg_color = imagecolorallocate($im, 240, 240, 240); imagefilledrectangle($im, 0, 0, 120, 40, $bg_color); } // 绘制干扰线(仅当GD可用时) if (function_exists('imageline')) { for ($i = 0; $i < 5; $i++) { $line_color = imagecolorallocate($im, rand(150, 200), rand(150, 200), rand(150, 200)); imageline($im, rand(0, 120), rand(0, 40), rand(0, 120), rand(0, 40), $line_color); } } // 绘制字符 $code = generate_captcha_code(); // 生成4位字母数字 $_SESSION['captcha_code'] = strtolower($code); for ($i = 0; $i < 4; $i++) { $char_color = imagecolorallocate($im, rand(50, 100), rand(50, 100), rand(50, 100)); imagestring($im, 5, 25 + $i * 20, 12, $code[$i], $char_color); } // 输出图像 header('Content-Type: image/png'); imagepng($im); imagedestroy($im);

提示imagestring()的字体大小参数5对应内置字体,无需额外文件。若发现验证码文字模糊,将imagestring($im, 5, ...)改为imagestring($im, 4, ...)减小字号,或增加imagesetthickness($im, 2)加粗线条。

3.2Verify_your_identity.php:带会话绑定的挑战流程

验证码不是独立页面,而是嵌入在防护链中的环节。当check_request_rate()返回trueanti_ddos.php会重定向到Verify_your_identity.php?redirect_url=/target.php,该文件执行三步操作:

  1. 会话校验:检查$_SESSION['fingerprint']是否匹配当前请求指纹,防止攻击者绕过
  2. 挑战生成:调用securitecode.php输出验证码,并将$_SESSION['captcha_time'] = time()记录生成时间
  3. 表单渲染:输出含隐藏字段<input type="hidden" name="fingerprint" value="<?= $fingerprint ?>">的HTML表单

关键安全设计在Verify_your_identity_LASTCHANCE.php(最后一道防线):当用户提交验证码后,不仅校验$_POST['captcha']是否等于$_SESSION['captcha_code'],还检查time() - $_SESSION['captcha_time'] < 300(5分钟有效期),且$_POST['fingerprint'] === $_SESSION['fingerprint']。这杜绝了验证码被截获后重放攻击。

3.3 前端集成:最小侵入式接入方案

无需修改现有HTML,只需在入口文件(如index.php)顶部插入:

<?php // 防CC攻击入口 require_once './anti_ddos.php'; ?>

anti_ddos.php会自动检测请求路径,对敏感接口(/login.php,/api/等)启用防护,对静态资源(.css,.js,.jpg)跳过。若需自定义保护路径,在config.php中修改:

$protected_paths = [ '/login.php', '/register.php', '/api/order', '/search.php' ];

前端无需任何JS适配——验证码表单提交后,Verify_your_identity.php处理成功则header("Location: {$_GET['redirect_url']}")跳回原页面,失败则刷新验证码。整个过程对用户透明,仅增加一次302跳转延迟(约50ms)。

4. 黑名单持久化与日志分析实战:从防御到溯源

4.1config.php驱动的内存+文件双模黑名单

黑名单存储在config.php定义的$blacklist_file = './config/blacklist.txt';中,格式为IP|timestamp|reason,例如:

192.168.1.100|1715234567|captcha_failed_3_times 203.204.205.206|1715234589|exceed_rate_limit

anti_ddos.phpblock_ip()函数中写入黑名单:

function block_ip($ip, $reason = 'unknown') { $blacklist_file = './config/blacklist.txt'; $entry = "$ip|" . time() . "|$reason\n"; file_put_contents($blacklist_file, $entry, FILE_APPEND | LOCK_EX); // 同时写入内存数组(本次请求有效) $_SESSION['blocked_ips'][] = $ip; }

注意:内存数组$_SESSION['blocked_ips']仅在当前会话有效,重启PHP-FPM后清空;文件黑名单永久生效。两者结合既保证实时性,又避免重启丢失。

4.2 日志解析:用Linux命令快速定位攻击源

./logs/attack_log.txt记录所有拦截事件,格式为[TIMESTAMP] [ACTION] message。用以下命令快速分析:

# 统计近24小时被拦截最多的IP awk -F'\\|' '/BLOCKED/ && $1 > systime()-86400 {print $3}' ./logs/attack_log.txt | sort | uniq -c | sort -nr | head -10 # 查看某IP的详细攻击路径 grep "192.168.1.100" ./logs/attack_log.txt | tail -20 # 统计验证码触发次数(判断是否被绕过) grep "CAPTCHA_SHOWN" ./logs/attack_log.txt | wc -l

若发现某IP在blacklist.txt中存在但仍在请求,检查其是否使用代理池轮换IP——此时需在config.php中启用$enable_user_agent_fingerprint = true;,将UA哈希加入黑名单键值。

4.3 攻击模式识别:从日志中提取业务层特征

真正的CC攻击往往有业务特征。例如电商站被刷优惠券,日志中会出现大量/api/coupon/use?code=ABC123;论坛被灌水,则/api/post/create?content=...高频出现。用grep提取关键参数:

# 提取所有coupon code grep '/api/coupon/use' ./logs/attack_log.txt | sed -n 's/.*code=\([^&]*\).*/\1/p' | sort | uniq -c | sort -nr # 提取POST内容长度(判断是否机器生成) awk -F'\\|' '/BLOCKED/ && /POST/ {print length($4)}' ./logs/attack_log.txt | sort -n | tail -5

若发现code字段高度重复(如ABC123出现500次),说明攻击者未随机化参数,可在core2.phpgenerate_request_fingerprint()中加入parse_str($_POST, $post_data); $fingerprint .= md5(json_encode($post_data));强化指纹。

5. 生产环境部署 checklist 与性能压测验证

5.1 五步上线检查清单

步骤操作验证方式风险提示
1. 权限检查确认./logs/./config/目录可写touch ./logs/test && rm ./logs/test若失败,chmod 755 logs config,切勿777
2. GD扩展验证运行php -m | grep gd若无输出,联系主机商启用GD无GD则验证码降级为文本,安全性下降
3. 会话配置检查phpinfo()session.save_path是否可写ls -ld $(php -r "echo ini_get('session.save_path');")若不可写,修改php.ini或在anti_ddos.php开头加session_save_path('./tmp');
4. 敏感路径注册config.php$protected_paths中添加业务接口访问/login.php应触发防护,访问/style.css不应触发漏加路径=防护缺口;多加静态资源=影响性能
5. 日志轮转创建logrotate配置/etc/logrotate.d/php-anti-ddoslogrotate -d /etc/logrotate.d/php-anti-ddos避免attack_log.txt无限增长撑爆磁盘

5.2 Apache Bench压测对比:防护开启前后的QPS变化

ab工具实测防护效果(测试环境:CentOS 7 + PHP 7.4 + Nginx):

# 关闭防护时基准测试 sed -i 's/define("ANTI_DDOS_ENABLED", true)/define("ANTI_DDOS_ENABLED", false)/' anti_ddos.php ab -n 1000 -c 50 http://localhost/login.php # 开启防护后测试(同一脚本) sed -i 's/define("ANTI_DDOS_ENABLED", false)/define("ANTI_DDOS_ENABLED", true)/' anti_ddos.php ab -n 1000 -c 50 http://localhost/login.php

典型结果:

  • 无防护:QPS 120,平均响应时间 85ms,错误率 0%
  • 有防护:QPS 95(-21%),平均响应时间 112ms(+32%),错误率 0%,但./logs/attack_log.txt新增12条[BLOCKED]记录

关键结论:性能损耗集中在验证码生成环节(securitecode.php的GD运算),若QPS下降超30%,需启用$enable_captcha_cache = true;(在config.php中),让同一指纹5分钟内复用验证码图片,减少GD调用。

5.3 误报率验证:用真实用户行为脚本模拟

编写test_normal_user.php模拟正常操作:

<?php // 模拟用户:首页->搜索->查看详情->加入购物车 $urls = [ 'http://localhost/', 'http://localhost/search.php?q=phone', 'http://localhost/product.php?id=123', 'http://localhost/cart.php?action=add&id=123' ]; foreach ($urls as $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt'); curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt'); curl_exec($ch); curl_close($ch); usleep(200000); // 间隔200ms } ?>

运行10次,检查./logs/attack_log.txt中是否有NORMAL_USER_BLOCKED记录。若有,说明$max_requests_per_minute设得太低,需上调至业务允许的峰值。

最后,打开./logs/attack_log.txt,找到最新一条[BLOCKED]记录,复制其IP,然后执行:
grep "192.168.1.100" ./logs/attack_log.txt | head -5 | awk -F'|' '{print $4}' | sort | uniq -c | sort -nr | head -1
这条命令将输出该IP最常访问的URL路径,它很可能就是攻击者瞄准的业务接口。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 14:04:47

MATLAB实现LVQ人脸识别:小样本、可解释、轻量部署

简介&#xff1a;本资源是一套基于LVQ&#xff08;学习向量量化&#xff09;神经网络的人脸识别完整MATLAB实现方案&#xff0c;面向机器学习初学者及算法实践者&#xff0c;聚焦模式识别中的分类预测任务&#xff0c;特别适用于课程设计、课程实验与小规模人脸数据建模验证。压…

作者头像 李华
网站建设 2026/9/16 14:04:20

中医大夫助理Android源码解析:SQLite与ListView实践

简介&#xff1a;这是一份面向Android开发者与中医信息化方向学习者的完整项目源码&#xff0c;实现中医大夫在诊断、病历记录与中药知识查询方面的辅助功能。源码包共125个文件&#xff0c;压缩包约1.55MB&#xff0c;涵盖20个Java源文件、49个class文件、16个XML布局与配置文…

作者头像 李华
网站建设 2026/9/16 14:04:06

双层车辆路径问题(2E-VRP)MATLAB实现与ABC算法解析

简介&#xff1a;本资源是面向物流优化研究者与运筹学初学者的双层车辆路径问题&#xff08;2E-VRP&#xff09;Matlab求解方案&#xff0c;聚焦城市多级配送场景下的成本与路径协同优化&#xff0c;适用于高校课程设计、科研建模及智能算法实践。压缩包共31个文件&#xff0c;…

作者头像 李华
网站建设 2026/9/16 14:02:09

Flask项目CSRF防护原理与实践指南

1. Flask项目中的CSRF攻击与防护原理跨站请求伪造(CSRF)是一种常见的Web安全威胁&#xff0c;攻击者诱骗用户在已认证的Web应用中执行非预期的操作。想象一下这样的场景&#xff1a;用户登录了银行网站后&#xff0c;又访问了恶意网站&#xff0c;后者悄悄向银行网站发送转账请…

作者头像 李华
网站建设 2026/9/16 14:00:10

多微信管理系统源码解析:ThinkPHP6多应用与队列实践

简介&#xff1a;一套基于ThinkPHP6框架的多微信管理系统源码&#xff0c;前端采用X-admin2.2与layui2.5.x&#xff0c;面向需要同时运营多个微信公众号、并将微信支付对接到对应企业商户的PHP开发者。无需接入微信开放平台即可完成多公众号管理与支付路由&#xff0c;框架结构…

作者头像 李华