框架无关、即插即用的 PHP 防火墙,专门对抗 HTTP 洪水 / 爬虫刷接口 / 恶意扫描。
在入口文件顶部 require_once 一行即可启用,无需 Composer、无需数据库、不改动业务代码。
白名单优先、黑名单硬拦,再到静态放行 / 放行路径 / UA 规则 / 限频,最后用 JS 人机验证拦下脚本流量。
真人浏览器几十毫秒算完令牌自动跳转;curl / python-requests 不执行 JS 被挡门外。
自动探测 Redis > Memcache / Memcached > 文件,没有也能跑(虚拟主机友好)。多站点共用一台缓存时键前缀自动隔离。
任意异常都放行,绝不白屏宿主站点;先 observe 观察,确认无副作用再开 on。
黑名单支持单 IP / CIDR / 起止段 / 通配 / IPv6,覆盖现代网络环境。
<?php
// 放在入口文件(index.php / app.php / public/index.php)的最顶部
require_once __DIR__ . '/cc-shield/bootstrap.php';
一款离线运行的 Windows 桌面程序(exe),把防火墙日志变成可读的攻击情报。
内置离线 IP 库(ip2region),自动解析每条攻击的省 / 市 / 运营商,无需联网。
按 /16 网段与归属地两种维度聚类,一眼看出攻击来自哪些机房与地区。
按小时维度统计攻击密度,识别攻击高峰与持续时长。
区分黑名单 / UA 规则 / 限频 / 挑战洪水,定位主要拦截手段。
标注疑似误拦记录,帮助你在上线前把真实用户排除在防护之外。
PyQt5 打包的单目录 exe,配套离线库,解压后双击即可运行,不写注册表。
cc-shield.log(Tab 分隔 7 列:时间 / 动作 / 阶段 / IP / 原因 / URL / UA)。
防火墙开启后产生的日志,直接拖进分析器即可。
CC Shield 是纯 PHP 实现,零扩展依赖。以下为经过实测与推荐的组合。
CC_SHIELD_ALLOW_CLI 强制)random_bytes()、\Throwable)ip2long() 返回有符号整数,会导致 ≥128.0.0.0 的高位 IP 段匹配偏差。redis(推荐)memcached / apcucc-shield/data/ 需可写除了 10 层 CC 防护,CC Shield 还内置一层链接/查询串注入防护(第 2 层,默认开启), 专门拦截通过 URL 发动的历史漏洞攻击特征。
PHP-CGI 参数注入 · 未授权 RCE · Critical
拦截 %ad / %2d 等注入特征——攻击者借此向 php-cgi.exe 注入 -d 指令实现远程代码执行。
旧版 PHP-CGI 参数注入
CVE-2024-4577 正是它的绕过;同样依靠 URL 特征拦截。
经典 URL 绕过
拦截 %00 等空字节注入,防御路径 / 包含类绕过尝试。
0xAD 同时也是 UTF-8 的续字节——
「中」的编码 %E4%B8%AD 里就含 %AD。所以本层不是简单匹配
%ad(那会误拦约 3.1% 的常用汉字,让用户搜索「中 / 字 / 六」时直接 403
「该页无法显示」),而是要求 0xAD 前一字节为非高位字节(即它不属于任何
多字节字符),仅在「参数边界 + 后跟开关字符 + 典型载荷关键词」时才判定为注入。mbstring,也不会误伤 base64 值里的 -d;
已通过 422,340 组多字节字符穷举回归(CJK 基本区 / 扩展 A·B / 谚文 / 假名 / emoji),零误拦。
cc_shield_env_check_用完即删.php:上传到网站根目录访问即可一键检测
(PHP 版本 / SAPI / 架构 / 扩展 / 历史漏洞逐步判定),查看完请立即删除。
下载检测工具(重命名为 .php 后使用)
CC Shield 零配置即可运行(默认 mode = on),并不强制要求改配置才能启动。
但上线前,建议通过 config/shield.ini 微调几项,避免误拦真实用户。
cc-shield/config/shield.ini · 格式:扁平 key=value(无 section) · 保存即生效,无需重启 PHP / Web 服务器
; 运行模式:先 observe 观察 1~2 天,确认无副作用再改 on
mode = observe
; 走 CDN / Nginx 反代必须开 1;直连服务器保持 0(防 XFF 伪造绕过)
trust_xff = 0
; 后台 / API / 健康检查,命中即绕过防火墙
allow_paths = "/admin,/api/,/wp-admin,/wp-login.php"
; 自己的办公 / 运维 IP,强烈建议填写,防误锁自己
ip_whitelist = "1.2.3.4, 10.0.0.0/8"
mode:先用 observe 观察,再开 ontrust_xff:CDN / 反代开 1,直连保持 0allow_paths:把后台、API 加进去ip_whitelist:填你的办公 / 运维 IPblock_empty_ua / min_ua_len:过短 UA 直接拦ua_blacklist / ua_allow:恶意工具 / 搜索引擎crawler_ips:爬虫来源 IP(默认已内置官方段)crawler_dns_verify:反向 DNS 校验爬虫来源challenge_max / challenge_hard_max:人机验证的软上限(超了只记日志、不封禁,默认 300)与硬上限(超了才 403,默认 3000)challenge_paths:只对敏感入口挑战,大幅降低挑战总量token_bind_ip / token_bind_prefix_v4:令牌绑定粒度;移动网络 / CGNAT 出口 IP 漂移时设 24 按网段绑定(比直接设 0 安全)store_type:auto / redis / memcache / memcached / file(APCu 需显式指定,见下)store_prefix:缓存键前缀。留空即自动隔离——多项目共用一台 Memcache / Redis 时互不干扰;仅多站共用同一份包且文档根也相同时才需手工指定log_level:all / action / block / offdefine() 覆盖(优先级更高),或用 CC_SHIELD_CONFIG 数组配置限频分组等数组型参数。完整参数说明见压缩包内的 README.md。
data/ip-blacklist.txt,命中即拦,不受放行路径、静态后缀、爬虫 UA 影响;改完保存即生效。唯一能覆盖黑名单的是 ip_whitelist——把自己办公 / 运维 IP 加白,避免误锁。
trust_xff,再设 token_bind_prefix_v4 = 24 按网段绑定,最后才考虑 token_bind_ip = 0;auto 已不再选 APCu(其缓存按 PHP 进程隔离,会造成间歇性拦截),需要更快的共享存储请用 Redis / Memcached;data/.salt 签名,各机各一份盐 → 令牌只在签发它的那台有效。请共用同一 data/ 或统一 CC_SALT;cc_shield_env_check_用完即删.php 放到网站根目录访问,它的「挑战令牌往返自测」会读取你浏览器真实携带的令牌并当场判定
没有携带 / ✅ 通过 / ❌ 未通过,原因 xxx——刷新几次再看不携带/未通过,就是问题所在。
ua_allow」不再等于放行——还必须通过来源校验,否则一律按普通访客处理
(照样受限频与人机验证约束):crawler_ips:来源 IP 必须落在官方网段内,默认已内置 Googlebot / Bingbot / Baiduspider 官方段,无需填写即可用;crawler_dns_verify = 1:改用反向 DNS 双向确认(官方推荐、名单永不过期,代价是少量 DNS 查询,已带缓存与每分钟限流);trust_crawler_ua = 1:仅凭 UA 放行,不安全,仅为兼容旧行为,默认关闭。curl -A "Googlebot/2.1" http://你的站/ 应收到 403 或人机验证页,而不是正常页面。
把 cc-shield/ 目录整体拷到你的项目根目录,在入口文件最顶部加一行:
require_once __DIR__ . '/cc-shield/bootstrap.php';
在引入前加 define('CC_SHIELD_MODE','observe'); 跑 1~2 天,
看 data/cc-shield.log 里的 WOULD_BLOCK,确认无真实用户被误判。
把后台路径、API 前缀、办公 IP 填进 config/shield.ini,再把模式改成 on。
双击打开日志分析器,把 cc-shield.log 拖入,按归属地 / 网段 / 时段 / 拦截类型查看攻击全貌。
两个独立压缩包 + 一个单文件检测工具,按需取用。下载后解压 / 上传即可,无需安装。
不会。它只读取 $_SERVER / $_COOKIE,不依赖任何框架,且在业务启动前运行;被拦的请求根本不会进到框架,通过的请求原样交还。务必放在入口最顶部。
开启 trust_xff(或 CC_TRUST_XFF),让它从 X-Forwarded-For / X-Real-IP 取真实访客 IP。直连服务器切勿开启,否则攻击者可用 XFF 伪造绕过。
不会。搜索引擎爬虫从官方 IP 段来访时直接放行——默认已内置 Googlebot / Bingbot / Baiduspider 官方网段,也可开 crawler_dns_verify 改用反向 DNS 校验(官方推荐、名单不会过期)。真实浏览器首次访问做几十毫秒验证后自动跳转,几乎无感。挑战只对 GET 请求,POST 表单不受影响。
不能(前提是别开 trust_crawler_ua)。因为 UA 可以随意伪造,爬虫白名单默认必须校验来源:只有「UA 命中 ua_allow」且「来源 IP 在官方网段内(或反向 DNS 双向确认通过)」才放行。伪造 UA 的请求会退回普通队列,照样受限频与人机验证约束。
自测:curl -A "Googlebot/2.1" http://你的站/ 应收到 403 或验证页。
能。store_type=auto 会自动退回文件存储:非阻塞加锁(拿不到锁就直接放行,绝不卡住请求)、rename 原子写、并按概率自动回收过期缓存文件。并发量大的站点建议上 Redis。
默认不会,已自动隔离,无需配置。但要理解原理,否则出问题时很难查:
Memcache / Redis 的键空间是整台服务器共享的,而各站用到的键名都一样(ban:IP 临时封禁、r:组:IP:槽 限频计数、c:IP:槽 挑战次数、botdns:IP 爬虫 DNS 缓存)。不隔离就会跨站连坐:A 站封的 IP 在 B 站也被封、几个站的访问量叠加到同一个计数器上把限频阈值提前打满、误封真人、爬虫 DNS 配额被别站吃光。
本版为每个安装派生唯一的键前缀(形如 cshr:9f3a1c7e02:ban:1.2.3.4),依据是「站点文档根 + 本包目录」,所以这两种常见形态自动隔离:「各项目各拷一份 cc-shield」→ 包目录不同;「多站点共用一份 cc-shield」→ 文档根不同。用文件存储时本来就各用各的 data/cache/,天然隔离。
唯一例外:多个站点共用同一份包、且文档根也相同(同一站点下 /a/、/b/ 两个子项目各引一份),此时需手工区分——各站写不同的 store_prefix = "cshr:siteA" / "cshr:siteB",或在入口 define('CC_STORE_PREFIX', ...)。核对办法:跑 cc_shield_env_check_用完即删.php 看「缓存键前缀」一行,各站点必须不同。
这类症状几乎都出自有状态层(限频、临时封禁、人机验证)或请求被挂住,按下面三步定位:
① 先分清是「403 页面」还是「浏览器提示无法访问」。看到 403 说明是防火墙拦的,去 data/cc-shield.log 看第 3 列阶段(iplist 黑名单 / ua UA 规则 / rate 限频 / challenge 人机验证 / url-injection URL 特征);如果是浏览器自身提示「该页无法显示」,那是请求被挂住/超时,不是拦截——请确认已用最新版 src/Store.php(早期版本 flock 会无限等锁)。
② 人机验证反复出现时,直接看日志里的 why=——它就是结论:no_cookie(cookie 没被带回)、ip_mismatch:IP(IP 漂移,令牌有效但换了个 IP)、bad_hex(盐变了,或令牌不是本机/本 IP 签发的)、iter_low(没真正执行 JS,属正常拦截)。count 持续增长才说明令牌确实没生效。
③ 用检测工具一次看全:把 cc_shield_env_check_用完即删.php 放到网站根目录访问,「挑战令牌往返自测」会读取你浏览器真实携带的 cc_vt 并用同一套规则验一遍,直接给出没有携带 / ✅ 通过 / ❌ 未通过,原因 xxx;同一页还有防火墙看到的 IP、存储后端是否跨进程共享、data/ 是否可写、日志分层统计与 why 分布。
auto 不再自动选 APCu 了?因为 APCu 的缓存是按 PHP 进程隔离的(PHP-FPM / IIS 多 worker 下每个进程各一份)。限频计数、临时封禁这类状态必须跨请求、跨进程一致,否则会出现「这个进程说封了、那个进程说没封」,表现为间歇性拦截、刷新几次又好了——极难排查。要更快的共享存储请用 Redis / Memcached;确实需要 APCu 才显式写 store_type = apcu。
不推荐。防火墙内部用 PHP 整数运算处理 32 位 IPv4 地址,32 位 PHP 的 ip2long() 返回有符号整数,会导致 ≥128.0.0.0 的高位 IP 段匹配偏差。请使用 64 位 PHP。
不需要。IP 归属地解析使用随包内置的离线库(ip2region),全程离线,适合在内网 / 隔离环境使用。
按以下顺序排查:
① 运行模式:若配置成 observe,只会写日志(WOULD_BLOCK)而不真正拦截,改回 on 即可;
② IP 对不对:服务器实际看到的 IP 必须和黑名单里的一致。走 CDN / 反向代理时要在入口开 CC_TRUST_XFF,并确认取到的是真实访客 IP 而不是节点 IP;
③ 入口是否覆盖:确认你测试的这个 URL 所经过的入口文件确实 require 了 bootstrap.php(老系统常有多入口 / 静态文件直出,不经过 PHP);
④ 黑名单是硬拦截:现在命中即拦,不受放行路径、静态后缀、爬虫 UA 影响;唯一能覆盖它的是 ip_whitelist(这是为了不把你锁在门外)。
先看 data/cc-shield.log 里有没有 url-injection 记录:
① 有:是链接注入防护误判。只有早期版本会出现——它直接匹配 %ad,
而 0xAD 是 UTF-8 续字节,「中」的编码 %E4%B8%AD 里就含它,
因此会误拦约 3.1% 的常用汉字(中 / 字 / 六…)。升级到当前版本即可(已改为按
「是否为孤立软连字符」精确判定,42 万组穷举零误拦);紧急时可先在入口加
define('CC_URL_INJECTION_GUARD', false) 临时关闭本层。
② 没有:不是这一层,按上一条「黑名单不拦截」的思路逐项排查(模式是否为
observe、trust_xff、入口是否覆盖、限频阈值)。