ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

防红系统带后台无加密版:域名检测、切换与部署运维实践

防红系统带后台无加密版:域名检测、切换与部署运维实践 简介梦幻防红cos系统后台版是一套围绕网站防红场景设计的工具包主要面向个人站长、网站管理员及中小型在线平台用于解决DDoS攻击、恶意刷流量等导致的正常访问被拒绝问题。通过后台自定义防红接口管理员无需深入底层代码即可调整防护策略登录域名下的admin.php入口即可进行配置同时内置install.php一键安装逻辑当PHP版本不适配时只需切换至7.0版本即可完成部署降低了非专业用户的实施难度。资源压缩包共82个文件、总大小624KB其中包含64个PNG页面素材、8个CSS样式表、7个PHP核心功能文件以及JS脚本、TXT安装说明和JPG图片整体结构清楚界面素材与逻辑文件相互分离便于快速部署、查看和二次调整。目前已有108人学习使用适合流量较大、易受攻击的网站快速搭建可自主控制的防红机制为站点持续稳定运行提供实用保障。压缩包内的安装说明.txt记录了部署要点便于对照操作后台功能文件划分明确适合有二次开发需求的用户参考。1. 梦幻防红cos系统带后台版无加密先搞清楚你在部署什么做推广落地页和短链服务的人大概率遇到过这种场景链接刚发出去半小时在微信里点开就变成「已停止访问该网页」而同一台服务器用浏览器直开完全正常。所谓防红系统解决的是「同一个页面在不同聊天软件里可达性不一致」的问题——页面本身合规但域名被误判、被标记、被加入了拦截名单导致推广链路断裂。梦幻防红cos系统这类项目名字里的编号或代号可以不管真正做的事情就两类实时检测域名在各平台的访问状态以及在前端落地页按检测结果自动切换可用域名。带后台版意味着有独立的管理界面可以维护域名池、查看检测记录、开关策略开关。无加密则更具体PHP源码没有做混淆或扩展加密数据库结构和业务逻辑可以直接读、直接改。这对做二次开发的人是刚需因为域名检测的阈值、超时时间、切换策略如果封装成黑盒出了问题只能换项目。能打开源码看检测接口挂了之后是默默跳过还是直接报错是决定这套系统能不能在真实流量下跑稳的关键。这篇按部署一套「带后台、无加密」的防红系统顺序来讲先梳理检测与切换原理再本地跑通然后上生产配置最后落地到监控和二次开发。不依赖任何特定开源项目通用做法为主。2. 防红的底层逻辑域名检测、轮询切换与落地页匹配2.1 检测机制在检测什么拦截页面的特征识别平台拦截一个域名用户最终看到的不是一个HTTP错误而是一个平台自己的提示页。防红检测做的就是用服务端模拟请求去访问目标域名然后从响应内容里判断「这次访问是否被拦」。常见的拦截特征有三个层面。第一是状态码被拦时经常返回302跳到平台的安全提示页最终页面的HTTP状态可能是200或403单看状态码不够要看最终URL的host是不是平台的域。第二是页面标题关键词比如微信拦截页的标题会包含「已停止访问」「网页包含诱导分享」这类固定文案检测程序用正则匹配标题命中率极高。第三是响应体长度和敏感标记正常落地页的HTML体有一定结构被拦时返回的是一张提示图片加固定文案DOM结构简单到异常。实际工程里多数防红系统的做法是维护一组「拦截特征词库」每过一段时间检测一次只要命中特征之一就判定为红被拦截命中不了就放行。很重要的坑是用服务器本机curl去探测和你手机在微信内打开看到的可能不一样。因为平台拦截判定会结合请求UA、来源referer甚至是账号权重服务器模拟的UA太干净反而不会触发拦截。所以成熟的检测程序会伪装UA带上微信内置浏览器的X5内核标识有时还要带一个真实的referer地址。2.2 最小可用的域名检测函数在本地跑通之前先把最核心的检测函数写出来。这是一个不依赖框架的PHP函数输入一个域名和检测参数输出该域名当前的可访问状态。?php /** * 检测域名在指定平台是否被拦截 * param string $url 要检测的完整URL如 https://a.example.com/?id1 * param int $timeout 单次请求超时单位秒 * param array $keywords 拦截特征关键词列表 * return array [ok bool, code int, hit string] */ function checkDomainBlocked($url, $timeout 8, $keywords [已停止访问, 网页包含诱导, 被封禁]) { $ch curl_init(); curl_setopt_array($ch, [ CURLOPT_URL $url, CURLOPT_RETURNTRANSFER true, CURLOPT_TIMEOUT $timeout, CURLOPT_FOLLOWLOCATION true, CURLOPT_MAXREDIRS 5, CURLOPT_USERAGENT Mozilla/5.0 (Linux; Android 10; 微信 XWEB) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 MicroMessenger/8.0.30, CURLOPT_REFERER https://weixin.qq.com/, CURLOPT_SSL_VERIFYPEER false, CURLOPT_SSL_VERIFYHOST false, ]); // 只需要最终URL的host用来判断是否已被重定向到平台提示页 $finalUrl curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); $body curl_exec($ch); $code curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // 1. 如果最终落在平台的域名下直接判定为拦截 $blockedHosts [weixin110.qq.com, weixin.qq.com, c.pc.qq.com]; $finalHost strtolower(parse_url($finalUrl, PHP_URL_HOST) ?? ); foreach ($blockedHosts as $bh) { if (strpos($finalHost, $bh) ! false) { return [ok false, code $code, hit redirect_to_{$bh}]; } } // 2. 如果返回内容命中拦截特征词判定为拦截 foreach ($keywords as $kw) { if (mb_strpos($body, $kw) ! false) { return [ok false, code $code, hit keyword_{$kw}]; } } return [ok true, code $code, hit none]; }逻辑说明函数先跟随重定向拿最终地址再看最终host是否落在平台提示页域名下这是判断是否被拦的最快路径。接着用预设关键词去匹配响应体覆盖那种「状态码正常但页面内容已经被替换成提示页」的情况。最后返回一个结构化数组上层就可以拿这个结果做后续的域名切换。参数说明$timeout建议8到10秒之间太短误判率高移动网络下正常页面打开也要3到6秒太长检测任务会积压。$keywords里的词要跟着你实际观察到的拦截页文案走不同版本的客户端提示文案有差异生产环境建议每季度更新一次词库直接抓一次真实拦截页把标题和正文里的固定词补充进去。2.3 落地页如何决定跳到哪个域名检测脚本解决「知道哪个域名挂了」的问题落地页解决「用户来了往哪跳」的问题。常见的实现方式是落地页HTML里维护一份域名列表优先请求后端接口拿到当前可用域名的排序然后JavaScript在页面加载时执行跳转。一种轻量做法是接口只返回状态不返回页面内容// 页面加载后先从 /api/domain-list 拿到可用域名列表 fetch(/api/domain-list?site_id1) .then(r r.json()) .then(data { if (data.code 0 data.data.domains.length) { // 当前页面的域名如果不在可用列表里跳到第一个可用域名 const current location.hostname; if (data.data.domains.indexOf(current) -1) { location.replace(// data.data.domains[0] location.pathname location.search); } } }) .catch(() { // 接口挂了不要阻塞用户停留在当前页面即可 });这里有个容易被忽略的问题如果接口本身就部署在被封的域名下那前端请求接口也拿不到数据跳转逻辑直接失效。所以api接口域名和落地页域名必须解耦接口固定在独立域名或者直接部署在多个备用域名中都有的那台服务器上。跳转历史记忆也值得做。用户第一次通过A域名进来被切到B域名访问了内容下一次他在聊天记录里点开的仍然是A域名那条链接。体验好的做法是通过localStorage记录最近一次成功跳转的目标域名二次访问时不再请求接口直接跳记忆中的域名减少一步等待。2.4 域名池的组成与权重轮询策略参数建议值说明主域名数量1个作为默认下发地址流量优先走它备用域名数量3-5个分布在不同的DNS服务商避免一起被拔线检测间隔每5-10分钟太频繁容易被平台反制太稀疏切换不实时失败阈值连续2次判定拦截避免单次误判就把域名摘除恢复检测每30分钟一次被摘除的域名要周期性重测恢复后自动加回轮询策略上我见过最简单有效的是「主域名优先按权重切换」。主域名在线时100%流量走主域名主域名被摘除后请求转到备用域名池按数组顺序依次尝试。每次跳转前在前端再发一次轻量探测请求用204或200来判断备用域名此刻是否真的能打开能开才跳。这个策略的关键是把「服务端检测状态」和「用户实时探测」两层配合起来。服务端检测负责更新整体状态用户实时探测负责兜底两者即使有短暂状态不一致也不至于把用户带到打不开的域名上。3. 带后台版源码的结构拆分无加密版本地跑通的最小路径3.1 典型目录结构入口、后台与公共配置这类带后台的系统拿到手目录结构大同小异。一般来说会有四个区域前台落地页、后台管理界面、API接口层、安装与配置文件。下面是常见的布局project_root/ ├── index.php # 前台入口负责落地页展示与跳转 ├── admin/ │ ├── index.php # 后台登录入口 │ ├── dashboard.php # 后台首页展示域名状态总览 │ └── domain.php # 域名池管理页 ├── api/ │ ├── domain-list.php # 向前台下发可用域名列表 │ └── check.php # 手动触发某域名检测 ├── config/ │ ├── database.php # 数据库连接配置 │ └── settings.php # 全局参数如检测间隔、关键词库 ├── install/ │ └── install.sql # 初始化表结构 └── includes/ ├── function.php # 公共函数库 └── Detect.php # 检测逻辑封装类无加密带来的第一好处是这里可以直接进config/settings.php改参数不需要在后台找半天设置项。我看到很多项目的参数实际写死在代码里后台界面上只有一个「保存」按钮保存了也没生效原因就是后台写的是另一个变量名。源码可读的话先搜变量名再改能省很多排错时间。3.2 数据库初始化与最小表结构install.sql里一般会建多张表核心三张就够了域名表、检测记录表、用户表。域名表用来存储主域名和备用域名检测记录表存每次检测的结果用于展示趋势用户表是后台账号。CREATE TABLE domain_pool ( id int(11) NOT NULL AUTO_INCREMENT, domain varchar(190) NOT NULL COMMENT 完整域名不带http, type tinyint(1) NOT NULL DEFAULT 2 COMMENT 1主域名 2备用域名, status tinyint(1) NOT NULL DEFAULT 1 COMMENT 1正常 0被摘除, sort int(11) NOT NULL DEFAULT 0 COMMENT 排序权重越小越优先, remark varchar(255) DEFAULT COMMENT 备注如DNS服务商, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_domain (domain) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE check_log ( id bigint(20) NOT NULL AUTO_INCREMENT, domain_id int(11) NOT NULL DEFAULT 0, domain varchar(190) NOT NULL DEFAULT , result tinyint(1) NOT NULL DEFAULT 1 COMMENT 1通过 0拦截, hit_reason varchar(100) NOT NULL DEFAULT COMMENT 命中特征, checked_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_domain_id (domain_id), KEY idx_checked_at (checked_at) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;字段说明type字段区分主域名和备用域名是为切换逻辑服务的。sort权重字段要注意很多系统在后台界面上是拖拽排序但实际SQL查询时候用的是ORDER BY sort ASC整数越小越靠前别下意识以为是越大越靠前。check_log表要定期清理一天检测144次10分钟间隔5个域名就是720条数据一个月下来2万条不清理的话后台查询会变慢。3.3 用PHP内置服务器在本地跑通拿到源码第一件事不是配置nginx而是先用PHP自带的内置服务器在本地确认代码能跑。# 在项目根目录启动内置服务器端口选80或8080 php -S 0.0.0.0:8080 -t . # 如果在Windows下开发注意php命令要在PATH中或者写完整路径 # D:\phpstudy_pro\Extensions\php\php8.0.2nts\php.exe -S 127.0.0.1:8080 -t .启动后浏览器访问http://127.0.0.1:8080/如果页面是空白或直接弹出下载框优先检查config/database.php里的数据库账号密码。这一步跑通的意义是排除环境问题先把代码层面的事故面缩小到「能用内置服务器启动」的程度。注意内置服务器不支持public目录下的入口文件重写所以访问后台时要带路径。比如后台入口如果是admin/index.php那就直接访问http://127.0.0.1:8080/admin/index.php不要期待能省略index.php。这不代码有问题是PHP内置服务器的路由能力比nginx弱本地调试时访问完整路径即可。3.4 后台管理系统的登录态与入口逻辑后台的登录逻辑无外乎「表单提交账号密码比对数据库写入session」。不同项目差别在于校验方式有些是明文比对有些是md5后比对。无加密版本可以直接看login.php里的代码确认。重点检查两个点一是退出登录时是否销毁session二是登录成功后跳转是否带权限判断。这里给一个后台鉴权的通用模板做二次开发时照着写就行?php session_start(); // 未登录跳转到登录页 if (empty($_SESSION[admin_id])) { header(Location: /admin/login.php); exit; } // 可选的接口鉴权校验来源和token防止CSRF if (!empty($_POST) (!isset($_POST[token]) || $_POST[token] ! $_SESSION[token])) { http_response_code(403); exit(非法请求); }参数说明$_SESSION[admin_id]是登录标记很多系统只判断这一个变量存在一定的会话固定风险好在后台一般跑在内网或加了IP白名单攻击面不大。token校验是给后台里的「手动检测」「删除域名」这类POST操作加一层防跨站请求伪造的保险做二次开发时建议保留。4. 部署到生产伪静态、数据库配置与检测任务调度4.1 nginx伪静态规则与TinkPHP路由兼容很多防红系统基于TinkPHP或Laravel开发前台入口只有一个index.php其余路径全部交给路由解析。nginx下伪静态写不对最典型的症状是「首页能开内页404」。以TinkPHP的常见配置为例server { listen 80; server_name a.example.com; root /var/www/example/public; index index.php index.html; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; break; } } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { expires 7d; access_log off; } }配置说明rewrite ^(.*)$ /index.php?s$1是兼容TinkPHP pathinfo模式的写法把/index/check?urlxx这类路径统一到了index.php的s参数上。很多部署失败的原因在于root指向了项目根目录而不是public子目录导致nginx找不到入口文件。静态文件的expires 7d不是必须的但对落地页首屏有实际帮助降一次重复访问的静态资源请求量就少一次。4.2 域名池批量录入与状态同步上线前要把主域名和备用域名批量录入。直接在phpMyAdmin或命令行里操作SQL比较快后台界面适合运维时的单条增删。# 批量插入备用域名这样写可以避免重复插入报错 INSERT INTO domain_pool (domain, type, status, sort) VALUES (a.example.com, 1, 1, 0), (b.example.com, 2, 1, 10), (c.example.com, 2, 1, 20), (d.example.com, 2, 1, 30) ON DUPLICATE KEY UPDATE status VALUES(status);这里要特别提醒备用域名不要用同一家DNS服务商和同一个CDN账号。域名被封时如果所有备用域名都在同一账号下的同一个CDN里平台封禁可能是按CDN节点或按账号维度来的会出现「全灭」的情况。我见过最稳的做法是多个域名分别放在阿里云、腾讯云、Cloudflare三个不同服务商就算某一个平台的封禁规则再激进至少不会一次全废。另外域名要提前备案还是不需要取决于实际业务代码层面控制不了。但域名池里混用已备案和未备案的域名时检测结果会差异很大未备案域名在某些网络环境下本身就不可达会被误判为「拦截」。建议域名池只放同一资质等级的域名这样检测数据才有一致性。4.3 检测频率与失败阈值的关系检测频率和失败阈值是需要联合调的两个数。频率决定「发现域名挂了的速度」阈值决定「误判容忍度」。下面这组参数是经过实践的经验值配置项取值效果检测间隔300秒5分钟一轮发现被摘除的平均时延在5-10分钟单次超时8秒curl请求8秒无响应算失败连续失败阈值2次连续两次检测都判定拦截才执行域名摘除恢复检测间隔1800秒被摘除域名每半小时测一次恢复后自动加回池子摘除后保留时间24小时被摘除域名大于24小时不恢复自动通知管理员连续失败阈值设成2是为了抵抗单次误判。比如微信那边偶尔抽风对正常域名也返回一次拦截页过五分钟再测又正常了如果阈值为1这个域名就被白白摘除了。反过来阈值为3或以上时用户在这15分钟内访问主域名会发现打不开因为系统还在等待第三次检测结果出来。阈值2是「发现速度和误判率」的平衡点。4.4 部署期典型故障白屏、验证码不显示、接口超时部署期遇到的高频问题按出现概率排序如下后台登录页打开是白屏大概率是PHP报错被隐藏了。查看php.ini里display_errors是否为On或者在入口文件加一行ini_set(display_errors, 1);让错误显示出来。既然是无加密版本这一步是允许的生产环境再关回去。验证码不显示通常是GD库没装。Linux下执行apt install php-gd或yum install php-gd重启php-fpm就好。判断方法很简单PHP探针里看gd扩展是否存在不存在那验证码必然出不来不是代码问题。api接口请求超时先确认是不是被摘除域名的问题。有些项目接口地址写的是主域名主域名被封后接口自然不可达这时要在配置里把接口地址改到独立可用的域名或者改用IP访问测试。还有一个隐蔽问题是curl的CURLOPT_DNS_CACHE_TIMEOUT没设置DNS解析结果被缓存太久域名已经换了IP但curl还在用旧IP。显式设置curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 60)可以缓解。5. 把「无加密」用起来自己加一套域名健康度监控与通知5.1 基于cron的定时检测与通知脚本系统自带的检测任务可能只更新数据库状态但不会告诉你「主域名已经掉了快去处理」。自己写一个独立的监控脚本挂在cron上能在第一时间发通知。?php // monitor.php 独立监控脚本放在项目根目录 require __DIR__ . /includes/function.php; $pdo new PDO(mysql:hostlocalhost;dbnameyour_db, user, pass); $stmt $pdo-query(SELECT id, domain FROM domain_pool WHERE status 1 AND type 1); while ($row $stmt-fetch(PDO::FETCH_ASSOC)) { $url https:// . $row[domain] . /; $result checkDomainBlocked($url, 8); if (!$result[ok]) { // 连续第一次失败先不发通知等第二次确认 $failKey fail_ . $row[id]; $failCount (int)apcu_fetch($failKey) ?: 0; $failCount; apcu_store($failKey, $failCount, 600); if ($failCount 2) { sendDingTalk(域名被拦截 . $row[domain] . 命中特征 . $result[hit]); apcu_delete($failKey); } } else { apcu_delete(fail_ . $row[id]); } }监控逻辑说明脚本单独跑在cron里不依赖防红系统自带的调度器这样可以避免「系统整体挂了连监控都发不出来」的死锁。连续失败计数用APCu缓存保存存10分钟过期这样跨两轮检测5分钟间隔能凑齐2次失败才触发通知。cron配置示例*/5 * * * * /usr/bin/php /var/www/example/monitor.php /var/log/domain_monitor.log 21提示通知渠道可以用钉钉机器人Webhook也可以用Server酱之类的服务。如果都没有写一个发邮件的也行核心是「被摘除」和「恢复」两个事件必须通知日常正常检测结果不需要通知避免告警疲劳。5.2 给后台增加一个健康度趋势页系统自带后台多半只有「当前状态」列表没有历史趋势。既然是无加密版本在admin目录下加一个文件成本很低而且能做出一个类似vue3后台管理体系里常见的dashboard效果。新增接口返回近24小时检测数据按小时聚合?php // api/health-trend.php header(Content-Type: application/json; charsetutf-8); $pdo new PDO(mysql:hostlocalhost;dbnameyour_db, user, pass); $sql SELECT DATE_FORMAT(checked_at, %H:00) AS hour, COUNT(*) AS total, SUM(result 0) AS blocked FROM check_log WHERE checked_at DATE_SUB(NOW(), INTERVAL 24 HOUR) GROUP BY DATE_FORMAT(checked_at, %H:00) ORDER BY hour ASC; $rows $pdo-query($sql)-fetchAll(PDO::FETCH_ASSOC); echo json_encode([code 0, data $rows]);聚合说明result 0的计数是SQL里的布尔表达式求和MySQL会把true当1、false当0SUM(result 0)直接统计出拦截次数。前端拿这个JSON就能画出每小时拦截次数折线图用于观察平台封禁是否存在固定时间段规律。5.3 一个提升运维效率的小技巧主动预热即使系统没有自动恢复功能被摘除的域名在平台解封后用户也不会马上知道。手动去后台改状态太慢可以加一个「主动预热」机制监控脚本里对被摘除超过1小时的域名每小时主动访问一次如果连续两次检测正常自动把数据库里的status改回1让域名自动回归域名池。这个技巧的本质是把「人工确认解封」变成「自动探测自动恢复」。加了这个逻辑后备用域名池的存活率会明显上升因为很多域名的封禁其实是短时的24小时恢复检测间隔太长错过了解封后的一大波自然流量。到这里整个防红系统的可运维性才算完整检测有准度、切换有兜底、失败有通知、恢复无人工。剩下的就是根据实际业务的域名数量去调参数以及盯着前两周的检测日志看误判率了。本文还有配套的精品资源点击获取
返回列表