prowendi / hyperf-http-waf
A reusable Hyperf HTTP WAF middleware package for PHP 8.2+ with Swoole and OpenSwoole compatibility.
Requires
- php: ^8.2
- ext-json: *
- hyperf/config: ^3.0
- hyperf/contract: ^3.0
- hyperf/http-server: ^3.0
- psr/container: ^2.0
- psr/http-factory: ^1.1
- psr/http-message: ^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- psr/log: ^3.0
Requires (Dev)
- hyperf/di: ^3.0
- nyholm/psr7: ^1.8
- phpunit/phpunit: ^11.5
Suggests
- hyperf/logger: Required for channel-based WAF log routing (logging.channel config option)
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-01 09:01:30 UTC
README
prowendi/hyperf-http-waf 是一个面向 Hyperf 3.x+ 的独立 Composer WAF 扩展包,提供可复用的 HTTP 中间件、默认规则、真实 IP 解析、日志上报和可扩展规则体系,适配 PHP 8.2+ 与 Swoole / OpenSwoole 长驻内存模型。
特性
- 独立 Composer 包,可直接
composer require - 通过
ConfigProvider+ 默认配置接入,不绑定业务项目 - 支持全局中间件或路由级中间件注册
- 检测 Client IP / Method / Path / Query / Header / Cookie / Body / Upload / UA / Referer
- 支持 SQLi(含字符串恒真、注释、时间盲注、堆叠、Oracle 拼接、布尔恒真变体 TRUE/LIKE/
<>、HAVING/ORDER BY 探测、报错注入 EXTRACTVALUE/UPDATEXML、布尔盲注函数链、INTO OUTFILE/LOAD_FILE、系统 schema 访问、/*!50000union*/版本注释混淆、ORM 运算符注入op={"id":"GT"})、XSS(含任意事件处理器、javascript:/data: 协议变体)、命令执行(含 Windows 命令 mshta/bitsadmin/netsh)、反弹 shell(/dev/tcp、nc -e、socat)、PHP 代码执行串(eval/assert/preg_replace /e 等)、路径穿越(含..;/)、LFI(含php://流封装)、SSRF(含十六进制/十进制/八进制/IPv6 回环、AWS/GCP/阿里/腾讯/华为 metadata 及 IPv6 变体、gopher/dict 等危险协议)、反序列化(PHP 格式 + JavarO0AB/FastJSON"@type"Java 类名)、原型链污染(__proto__/constructor.constructor)、ThinkPHP filter 覆写与 invokefunction、Struts2 OGNL、NoSQL 运算符注入、XXE、JNDI(Log4Shell)、CRLF 头注入、SSTI(Jinja/FreeMarker)、JWT alg:none、null 字节参数、凭据泄露(AWS/阿里 LTAI/腾讯 AKID/Stripe/GitHub/Slack/私钥)、已知框架漏洞路径(think\app、BshServlet、druid、wls-wsat、xmlrpc.php 等)、恶意扫描器 UA、非法方法、输入规模异常 - Header 专项:Host 值含路径片段(Host 头注入绕过)、下划线转发头(
X_Forwarded_For伪造) - 上传文件内容嗅探:识别伪装扩展名的 Webshell(
<?php/JSP 声明)、脚本 shebang、SVG 内嵌脚本、Zip Slip 归档穿越条目(可通过files.content_inspection关闭) - 参数名与参数值同时扫描(覆盖
user[$ne]=类 NoSQL 注入、__proto__键注入) - 请求体无 Content-Type 或非文本类型时仍按原始数据扫描
- 超长值同时扫描头部与尾部切片,防止"填充绕过"
- 白名单路径匹配同时校验原始/解码/归一化路径,防止编码前前缀绕过
- 可选 LLM 提示词注入检测组(
llm-*规则,默认关闭):指令覆盖("ignore previous instructions")、系统提示词探测、伪造审批标记 —— 面向 AI 网关/Agent 场景按需开启 - 提供
observe与block两种模式 - 支持白名单、黑名单、可信代理、可信转发头
- 默认日志支持 PSR Logger,未接入时回退
error_log - 请求态数据不进入全局可变静态状态,适合协程与长驻内存
已知限制
- 超出
max_scan_length的值仅覆盖头部 + 尾部各一个窗口,攻击载荷藏在超长值中部且总分低于阈值时可能漏报 - UTF-7 等已过时浏览器编码不做归一化
observe模式只记录不拦截- 频率类攻击(爆破、验证码滥用、限流键轮换)需要跨请求状态,请在外层限流器处理
升级注意
- 从旧版本升级时请重新发布
waf.php:rules是数组,配置合并规则下用户已发布的rules会整体覆盖默认规则——不重新发布就拿不到新增规则(仅引擎层修复生效) trusted_proxies => ['*']/0.0.0.0/0会同时信任 IPv4 与 IPv6 来源- 白名单路径匹配会同时校验原始/解码/归一化三种路径变体——URL 编码了斜杠的正常客户端(如
/api%2Fv1/x)可能不再命中/api/*白名单,如有此类流量请把编码形式一并加入白名单 - 关闭
files.content_inspection后,非 seekable 上传流不会做内容嗅探(避免破坏性读取)
环境要求
- PHP 8.2+
- Hyperf 3.x+
- Swoole 或 OpenSwoole 运行时
安装
composer require prowendi/hyperf-http-waf
本包通过 composer.json 的 extra.hyperf.config 暴露 Prowendi\HyperfHttpWaf\ConfigProvider。标准 Hyperf 包加载流程下会自动发现。
如果宿主项目关闭了包配置自动发现,请显式加载 Prowendi\HyperfHttpWaf\ConfigProvider::class。
发布或复制配置
如果宿主项目安装了 hyperf/publisher,可执行:
php bin/hyperf.php vendor:publish waf-config
未安装发布命令时,直接复制:
vendor/prowendi/hyperf-http-waf/publish/waf.php
到宿主项目:
config/autoload/waf.php
全局中间件接入
在宿主项目的 config/autoload/middlewares.php 中注册:
<?php declare(strict_types=1); use Prowendi\HyperfHttpWaf\Middleware\WafMiddleware; return [ 'http' => [ WafMiddleware::class, ], ];
默认不自动强注册为全局中间件,避免在未评估误杀与性能成本前影响整个站点。
路由级中间件接入
按路由组接入:
<?php declare(strict_types=1); use Prowendi\HyperfHttpWaf\Middleware\WafMiddleware; use Hyperf\HttpServer\Router\Router; Router::addGroup('/admin', static function () { Router::get('/users', 'App\\Controller\\AdminController@index'); }, [ 'middleware' => [ WafMiddleware::class, ], ]);
如果项目使用控制器属性,也可以在控制器或方法上挂载 WafMiddleware::class。
通过 #[] 属性接入
本包提供了专用属性类 Prowendi\HyperfHttpWaf\Annotation\Waf,可以直接写成 #[Waf]。它内部继承自 Hyperf 官方的 Hyperf\HttpServer\Annotation\Middleware,默认指向 Prowendi\HyperfHttpWaf\Middleware\WafMiddleware。
最简写法:
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\GetMapping; use Prowendi\HyperfHttpWaf\Annotation\Waf; #[Controller(prefix: '/admin')] #[Waf] final class AdminController { #[GetMapping(path: 'dashboard')] public function dashboard(): array { return ['ok' => true]; } }
如果你需要控制中间件优先级,也可以传入 priority:
#[Waf(priority: 70)]
如果宿主项目更倾向直接使用 Hyperf 原生写法,也仍然可以继续使用 #[Middleware(WafMiddleware::class)]。
控制器级别示例:
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\GetMapping; use Prowendi\HyperfHttpWaf\Middleware\WafMiddleware; use Hyperf\HttpServer\Annotation\Middleware; #[Controller(prefix: '/admin')] #[Middleware(WafMiddleware::class)] final class AdminController { #[GetMapping(path: 'dashboard')] public function dashboard(): array { return ['ok' => true]; } }
方法级别示例:
<?php declare(strict_types=1); namespace App\Controller; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\PostMapping; use Prowendi\HyperfHttpWaf\Middleware\WafMiddleware; use Hyperf\HttpServer\Annotation\Middleware; #[Controller(prefix: '/api')] final class UploadController { #[PostMapping(path: 'upload')] #[Middleware(WafMiddleware::class)] public function upload(): array { return ['uploaded' => true]; } }
注意事项:
- 这种写法依赖宿主项目使用 Hyperf 的属性路由,例如
#[Controller]、#[AutoController]、#[GetMapping]、#[PostMapping]。 - 如果宿主项目是
config/routes.php或Router::addGroup()这种配置式路由,仍然应使用路由配置里的middleware数组。 - 如果一个控制器方法已经挂了多个中间件,Hyperf 3.x 可以重复写多个
#[Middleware(...)]。
最小配置
<?php declare(strict_types=1); return [ 'enabled' => true, 'mode' => 'observe', 'decision' => [ 'score_threshold' => 70, 'block_on_first_match' => true, ], 'trusted_proxies' => [ '10.0.0.0/8', '192.168.0.0/16', ], ];
配置说明
核心项
enabled: 总开关mode:observe或blockbody_size_limit: Body 检测读取上限,超过后只记规则不做全文扫描trusted_proxies: 可信代理 IP / CIDR,支持*表示信任任意上游代理trusted_headers: 可信代理下允许读取的真实 IP 头,支持*表示启用包内支持的全部真实 IP 头:x-forwarded-for、x-real-ip、forwardedallowed_methods: 允许的 HTTP 方法
决策项
decision.score_threshold: 累积分数拦截阈值decision.block_on_first_match: 命中action=block的规则时是否立即拦截
阈值项
thresholds.query_parameter_countthresholds.body_parameter_countthresholds.header_value_lengththresholds.max_value_lengththresholds.max_nested_depththresholds.max_scan_length
名单项
whitelist.ipswhitelist.cidrswhitelist.pathswhitelist.routeswhitelist.headerswhitelist.user_agentsblacklist.*
响应项
response.statusresponse.headersresponse.body
日志项
logging.enabledlogging.channellogging.body_max_lengthlogging.ua_max_lengthlogging.matched_sample_length
自定义规则
规则是结构化数组,每条规则至少包含:
rule_idnametypetargetpatternprefiltersscoreactionenabled
示例:
<?php declare(strict_types=1); return [ 'rules' => [ [ 'rule_id' => 'custom-rce-curl-pipe', 'name' => 'curl pipe shell', 'type' => 'rce', 'target' => 'input', 'pattern' => '/curl\\s+[^|]+\\|\\s*(?:bash|sh)/i', 'prefilters' => ['curl', '|', 'bash', 'sh'], 'score' => 80, 'action' => 'block', 'enabled' => true, ], ], ];
target 推荐取值:
input: 通用输入,适用于 query/body/header/cookiepathheadercookiebodyqueryua
切换 observe / block
只记录不拦截:
'mode' => 'observe',
启用拦截:
'mode' => 'block',
自定义白名单 / 黑名单
<?php declare(strict_types=1); return [ 'whitelist' => [ 'paths' => ['/health*', '/internal/callback*'], 'cidrs' => ['10.10.0.0/16'], 'headers' => [ 'x-internal-request' => ['1'], ], 'user_agents' => ['TrustedScanner'], ], 'blacklist' => [ 'ips' => ['203.0.113.9'], 'cidrs' => ['198.51.100.0/24'], ], ];
替换日志实现
默认实现为 Prowendi\HyperfHttpWaf\Logger\LoggerReporter:
- 优先使用宿主容器中的
Psr\Log\LoggerInterface - 若存在
Hyperf\Logger\LoggerFactory且配置了logging.channel,则按 channel 获取 logger - 否则回退
error_log
如需接入自定义上报器,在宿主项目中覆盖依赖:
<?php declare(strict_types=1); use App\Security\WebhookReporter; use Prowendi\HyperfHttpWaf\Contract\ReporterInterface; return [ 'dependencies' => [ ReporterInterface::class => WebhookReporter::class, ], ];
可观测字段
默认日志会记录:
timeclient_ipmethodpathactionrisk_scorehit_rulesua
并对以下字段脱敏:
passwordpasswdtokenaccess_tokenrefresh_tokenauthorizationcookiesecret
设计注意事项
- 不把请求态数据写入单例或静态可变属性
- 未配置
trusted_proxies时不盲信X-Forwarded-For - Body 只在大小阈值内做内容检测
multipart/form-data只检测文件元信息,不做大文件全文扫描- JSON 解析失败会优雅降级到轻量规则命中,不中断中间件链
测试
composer install
composer test
当前测试覆盖:
ConfigProvider与默认配置加载- 正常请求放行
- SQLi / XSS / 敏感路径命中
- 白名单放行
observe/block模式差异- 代理真实 IP 解析
- body size 限制
- 文件上传元信息检测
- Header 恶意载荷检测
未来增强方向
- Redis 动态封禁与滑动窗口
- 规则热更新
- Webhook / MQ / SIEM 上报器
- 路由维度细粒度策略
- 基于场景的误杀学习与调优