PHP防CC攻击系统源码拆解:请求频率限制与验证码拦截实战

📅 发布时间:2026/9/28 12:50:44
PHP防CC攻击系统源码拆解:请求频率限制与验证码拦截实战
简介这是一套面向PHP开发者的轻量级CC攻击防护系统源码适合运行PHP代码的网站用于学习与研究Web应用层安全防护。CC攻击通过模拟大量合法HTTP请求耗尽服务器资源本源码围绕请求频率限制、验证码验证、IP黑名单、异常行为检测、负载均衡与日志分析等思路提供了一套可参考的实战级防护方案帮助开发者理解并搭建基础防御机制。资源包共14个文件以7个php核心逻辑文件为主辅以6个txt说明文档和1个css样式文件压缩包约39KB结构紧凑便于快速阅读与二次修改。目前已有168人学习关注。通过研读这套源码读者可以掌握请求频率监控、验证码拦截、黑名单管理等关键实现方式并结合自身业务调整防护参数在安全性与性能之间寻找平衡进而提升项目的健壮性与自身Web安全认知。1. 一套能直接读源码的 PHP 防 CC 攻击系统到底值不值得拆流量正常、服务器 CPU 却莫名飙到 100%Nginx 的 access.log 里同一个 IP 每秒刷几十次search.php带宽没跑满但 PHP-FPM 进程全被占死——这是典型的 CC 攻击现场不是普通 DDoS。这套「简洁实用的 PHP 防被 CC 攻击网站系统源码」就是冲着这个场景来的它不依赖云 WAF不装扩展纯 PHP 文件丢进站点目录就能跑核心逻辑集中在anti_ddos.php、core2.php、securitecode.php这几个文件里配合Verify_your_identity.php做人机校验config.php管阈值参数。适合两类人一是手上跑着中小型 PHP 站、买不起高防又不想裸奔的站长二是想搞明白「请求频率限制 验证码 IP 黑名单」这套组合拳在代码层怎么落地的新手。它给的不是一个成品 SaaS而是一份能逐行读、能改参数、能嵌进自己项目的防护骨架。2. 拆开文件看设计请求频率限制和验证码是怎么串起来的2.1 目录结构里藏着的执行链路拿到压缩包解压后根目录下这几个文件不是随便堆的它们对应一条完整的拦截链路。先看清单文件作用是否需改动anti_ddos.php主入口负责调度检测逻辑需引入到站点公共头部core2.php核心计数与判定读写 IP 请求记录一般不改securitecode.php生成验证码图像不改Verify_your_identity.php验证码校验页面可改样式Verify_your_identity_LASTCHANCE.php二次拦截兜底页可改文案config.php阈值、时间窗口、黑名单开关必须按业务调start.php初始化与目录权限检查首次运行看一次css/flottant.css验证码页浮动样式可选链路是这样的用户请求先经过anti_ddos.php它调用core2.php读取该 IP 在当前时间窗口内的请求次数没超阈值就放行超了就跳到Verify_your_identity.php要求输入验证码验证码连续错或直接不提交最终落到Verify_your_identity_LASTCHANCE.php并写入黑名单。config.php是这条链路的调节旋钮所有「多少次算异常」「封多久」都在这里定。2.2 请求频率限制的计数逻辑与参数CC 攻击的本质是「单位时间内单 IP 请求数异常」所以第一道闸就是计数。core2.php常见做法是用文件存储不依赖数据库降低部署门槛每个 IP 对应一个记录文件内容大致是「时间戳:次数」。下面是我按这套源码逻辑还原的核心片段方便你对照理解?php // core2.php 计数核心逻辑还原 function checkRequest($ip, $config) { $dir $config[data_dir]; // 记录文件存放目录 $file $dir . md5($ip) . .txt; // 用 md5 避免 IP 直接做文件名 $now time(); $window $config[time_window]; // 时间窗口单位秒 $limit $config[max_requests]; // 窗口内允许的最大请求数 if (!file_exists($file)) { file_put_contents($file, $now . :1); return true; // 首次访问放行 } $data explode(:, file_get_contents($file)); $firstTime (int)$data[0]; $count (int)$data[1]; if ($now - $firstTime $window) { // 超出时间窗口重新计数 file_put_contents($file, $now . :1); return true; } $count; file_put_contents($file, $firstTime . : . $count); return $count $limit; // 未超限放行超限返回 false }逻辑说明每个 IP 一个文件记录「窗口起始时间」和「累计次数」。请求进来先判断是否还在同一个时间窗口内是就累加不是就重置。max_requests和time_window的比值决定了判定灵敏度。参数怎么设我一般会按业务峰值来反推正常用户浏览一个页面平均触发 35 个请求含静态资源走 CDN 的话更少如果time_window设 60 秒max_requests设 120相当于允许单 IP 每分钟 120 次请求对普通资讯站够用但如果你站内有大量 AJAX 轮询接口这个值要往上抬否则正常用户会被误伤。这是血泪经验——阈值调太紧第一个被拦的往往是你自己。2.3 验证码介入的时机与校验流程光靠计数拦截有个问题攻击者控制大量肉鸡每个 IP 只发几次请求单 IP 计数永远不超阈值但总量依然压垮服务器。所以这套源码在计数超限后不是直接封而是弹验证码——因为肉鸡能伪造请求头但很难自动过验证码。securitecode.php负责生成图像Verify_your_identity.php负责校验流程如下?php // Verify_your_identity.php 校验逻辑还原 session_start(); if ($_SERVER[REQUEST_METHOD] POST) { $input strtoupper(trim($_POST[code] ?? )); $real $_SESSION[verify_code] ?? ; if ($input $real) { // 验证通过给该 IP 发放一段时间的通行标记 setcookie(passed_check, md5($_SERVER[REMOTE_ADDR]), time() 1800, /); header(Location: /); exit; } else { // 验证失败累计失败次数 $_SESSION[fail_count] ($_SESSION[fail_count] ?? 0) 1; if ($_SESSION[fail_count] 3) { header(Location: Verify_your_identity_LASTCHANCE.php); exit; } } }逻辑说明验证码答案存在 session 里用户提交后做全等比较。通过后写一个 cookie 作为「已通过」标记有效期 1800 秒这段时间内该 IP 不再被计数拦截。失败累计 3 次就跳兜底页。参数上cookie 有效期是体验和安全的平衡点——设太短用户频繁过验证码会烦设太长等于给攻击者留了后门。常见做法是 1530 分钟。注意setcookie的路径参数要设成/否则只在当前目录生效站内其他页面照样被拦。3. 部署到自己的 PHP 站从引入到参数调优的完整步骤3.1 把防护逻辑挂到站点入口这套源码不是独立运行的它要嵌进你现有站点的请求入口。最省事的做法是在公共头部文件比如header.php或框架的中间件顶部引入anti_ddos.php。假设你的站点根目录是/var/www/html操作步骤# 1. 解压源码到站点下的防护目录 cd /var/www/html mkdir anti_ddos_system unzip PHP防被CC攻击网站系统源码.rar -d anti_ddos_system/ # 2. 给数据目录写权限计数文件要写入 chmod -R 755 anti_ddos_system/ chmod -R 777 anti_ddos_system/data/ # 若源码未自带 data 目录则手动建 # 3. 确认 PHP 版本与 GD 库验证码依赖 php -m | grep -i gd然后在你的公共入口文件最顶部加一行?php // 引入防护入口必须放在所有输出之前 require_once __DIR__ . /anti_ddos_system/anti_ddos.php;逻辑说明anti_ddos.php内部会读取config.php并调用core2.php做判定所以引入顺序不能乱。放在所有输出之前是因为它可能触发header()跳转一旦前面有 HTML 输出就会报「headers already sent」。GD 库是验证码生成的前提php -m里没有gd的话securitecode.php会直接报错验证码页变白屏。这是部署阶段最常见的翻车点。3.2 config.php 参数怎么按业务调config.php是整套系统唯一需要你认真改的文件。典型配置项和调参建议?php // config.php 关键参数 return [ time_window 60, // 统计窗口秒 max_requests 120, // 窗口内单 IP 最大请求数 block_time 3600, // 黑名单封禁时长秒 data_dir __DIR__ . /data/, enable_blacklist true, // 是否启用 IP 黑名单 whitelist [ // 白名单 IP不参与计数 127.0.0.1, 你的服务器出口IP, ], ];参数说明time_window和max_requests要一起看比值才是真正的「速率上限」。block_time决定攻击 IP 被封多久设太短攻击者换个时间又来设太长万一误封正常用户恢复慢3600 秒是常见折中。whitelist一定要把你自己的运维 IP、监控探针 IP、CDN 回源 IP 加进去否则监控系统频繁请求会被当成攻击源封掉到时候网站「假死」你连后台都进不去。我一般会先把max_requests设得宽松一点比如 300观察几天 access.log 里的真实分布再往下压。3.3 验证码页面的样式与体验调整Verify_your_identity.php默认输出比较朴素css/flottant.css控制浮动布局。如果你站点有统一模板建议把验证码页也套进去否则用户从正常页面突然跳到一个裸 HTML 页会以为网站被黑了。改动点!-- Verify_your_identity.php 中嵌入站点头部 -- ?php include __DIR__ . /../你的模板/header.php; ? div classverify-box p访问过于频繁请完成验证后继续/p form methodpost img srcsecuritecode.php onclickthis.srcsecuritecode.php?Math.random() input typetext namecode maxlength4 placeholder输入验证码 button typesubmit提交/button /form /div ?php include __DIR__ . /../你的模板/footer.php; ?逻辑说明img的onclick加随机参数是为了点击刷新验证码不加的话浏览器会走缓存用户看到的还是旧图。maxlength4要和securitecode.php里生成的字符数一致否则用户多输一个字符永远校验不过。这一步不影响防护强度但直接影响误伤率——体验做不好正常用户过不了验证码等于自己把流量挡在门外。4. 避坑与排查这套源码实际跑起来会遇到的五个问题4.1 现象所有用户都被要求输验证码包括自己原因max_requests设得过低或者data_dir没有写权限导致计数文件写不进去每次请求都被当成「首次访问」重新计数逻辑判断失效后直接走拦截分支。另一个可能是服务器前面有 CDN 或反向代理$_SERVER[REMOTE_ADDR]拿到的是代理 IP 而不是真实用户 IP所有用户共用一个「代理 IP」的计数瞬间超限。解决先确认data/目录权限是 777 且 PHP 进程用户可写再检查是否走了 CDN如果走了要从X-Forwarded-For头里取真实 IP代码里加一段// 在 anti_ddos.php 取 IP 处替换 function getRealIp() { if (!empty($_SERVER[HTTP_X_FORWARDED_FOR])) { $ips explode(,, $_SERVER[HTTP_X_FORWARDED_FOR]); return trim($ips[0]); // 取第一个即客户端真实 IP } return $_SERVER[REMOTE_ADDR]; }注意X-Forwarded-For可以被伪造只有在确认流量经过你自己的代理时才可信否则攻击者随便填这个头就能绕过计数。4.2 现象验证码图片显示不出来一片空白原因PHP 没装 GD 库或者securitecode.php输出图像前有 BOM 头/空格导致header(Content-Type: image/png)失效。BOM 头是 Windows 编辑器保存 UTF-8 文件时常见的坑文件开头多了三个不可见字节图像输出就废了。解决php -m | grep gd确认扩展用xxd securitecode.php | head -1看文件头有没有efbbbf有的话用sed -i 1s/^\xEF\xBB\xBF// securitecode.php去掉。另外确认securitecode.php文件末尾没有多余空行。4.3 现象攻击停了但服务器还是慢data 目录文件堆积原因计数文件按 IP 生成攻击者用大量不同 IP 刷data/目录下会堆出成千上万个小文件文件系统 inode 耗尽ls都卡。这套源码默认没有自动清理机制。解决加一个定时清理脚本用 crontab 每小时跑一次删掉超过 2 小时没更新的计数文件# cleanup.sh find /var/www/html/anti_ddos_system/data/ -name *.txt -mmin 120 -delete# crontab -e 加入 0 * * * * /bin/bash /var/www/html/anti_ddos_system/cleanup.sh-mmin 120表示修改时间超过 120 分钟的文件这个值要大于time_window否则正在计数的文件被删了计数就断了。4.4 现象验证码通过了但刷新页面又要求验证原因setcookie的 domain 或 path 设置不对cookie 没写进浏览器或者站点是 HTTPScookie 没加secure标志被浏览器策略拦了。还有一种情况是 session 没配好session_start()失败导致验证码答案存不住。解决检查setcookie第四个参数 path 是否为/HTTPS 站点加上secure和httponlysetcookie(passed_check, md5($ip), [ expires time() 1800, path /, secure true, // 仅 HTTPS 传输 httponly true, // 禁止 JS 读取 ]);同时确认session.save_path可写session_start()前不能有任何输出。4.5 现象黑名单封了 IP但攻击流量一点没少原因这套源码的黑名单是应用层判断攻击流量已经打到 PHP 了才被拦PHP-FPM 进程照样被占用。应用层防护只能挡「请求频率不高但持续」的 CC挡不住「每秒上万请求」的洪水。另外如果攻击者用代理池封 IP 意义有限。解决应用层防护要和 Web 服务器层配合。Nginx 层加limit_req做第一道粗筛把明显异常的流量挡在 PHP 之前# nginx.conf 中 http 块 limit_req_zone $binary_remote_addr zonecc_zone:10m rate10r/s; # server 块中 location location ~ \.php$ { limit_req zonecc_zone burst20 nodelay; # ... 原有 fastcgi 配置 }rate10r/s是单 IP 每秒 10 个请求burst20允许突发 20 个nodelay表示突发也立即处理不排队。这样大部分 CC 流量在 Nginx 层就被挡了PHP 层的验证码只处理漏网的两层配合才稳。5. 进阶把防护做成可观测的而不是黑匣子这套源码默认只做拦截不记录「拦了谁、拦了多少」出了问题你只能靠猜。我一般会加一层轻量日志把每次拦截写进一个按天切分的文件方便事后分析攻击来源和调整阈值。改动点在anti_ddos.php判定为拦截的分支里?php // 拦截时记录日志 function logBlock($ip, $reason) { $logFile __DIR__ . /logs/block_ . date(Ymd) . .log; $line sprintf([%s] ip%s reason%s uri%s ua%s\n, date(Y-m-d H:i:s), $ip, $reason, $_SERVER[REQUEST_URI] ?? -, $_SERVER[HTTP_USER_AGENT] ?? - ); file_put_contents($logFile, $line, FILE_APPEND | LOCK_EX); }逻辑说明LOCK_EX防止并发写入时日志错乱按天切分避免单文件过大。记录uri和ua是为了区分「正常用户被误伤」和「攻击流量」——正常用户的 UA 是浏览器攻击脚本的 UA 往往是空的或者python-requests之类。跑几天后grep -c reasonrate block_*.log看拦截量如果某天突然暴涨说明阈值该调了或者真被打了。验证防护是否生效别只看「网站能不能打开」要做一次受控测试。用ab或curl模拟高频请求观察是否在预期次数后被拦# 模拟单 IP 高频请求看第几次被要求验证码 for i in $(seq 1 200); do curl -s -o /dev/null -w %{http_code} http://你的域名/ done echo如果前 120 次返回 200之后开始返回 302跳验证码页说明计数阈值生效。如果全程 200检查anti_ddos.php是否真的被引入了——很多人改了半天参数结果入口文件根本没 require白忙一场。还有个容易被忽略的点这套源码的计数是基于文件的多台服务器做负载均衡时每台机器各算各的攻击者轮流打不同节点单节点计数永远不超限。这种场景下要么把计数存储换成 Redis 共享要么在负载均衡层做会话保持。源码本身没带 Redis 版本但core2.php的计数逻辑抽出来改成 Redis 的INCREXPIRE并不难这是从单机防护走向集群防护的必经一步。从那以后我每次部署这类应用层防护都强制先跑一遍受控压测确认拦截阈值和日志都正常再挂到生产环境。不然等真被打了才发现防护没生效那才是真的后悔药都没得吃。希望帮到你。本文还有配套的精品资源点击获取