大家好,我是小皮。
基于 PHP 的安全攻击检测插件,支持 31 种攻击类型检测,兼容 Laravel、Webman、ThinkPHP、Hyperf 框架。
项目地址:https://github.com/erikwang2013/security-php
项目说明
Security PHP 是一个轻量级 PHP 安全中间件,通过正则模式匹配和结构分析检测常见的 Web 攻击载荷。每个检测器独立可配置(启用/禁用 + 拦截/日志模式),支持 IP 白名单(含 IPv4/IPv6 CIDR)、IP 攻击升级黑名单(5次/60s → 封禁15分钟)、字段白名单、日志轮转和去重。检测器可返回自定义 HTTP 状态码(405/413/415 等)。持久化数据支持 File/Redis/Cache 三种存储后端,可按需切换。
支持的攻击类型
注入类攻击
xss | <script>、事件处理器 on[a-z]+=、SVG/CSS 注入、javascript: URI |
sql_injection | /**/、( 绕过)、sleep/benchmark/pg_sleep、布尔盲注、schema 枚举、存储过程执行 |
command_injection | $()、管道符、/dev/tcp、PHP 代码执行函数、链式执行 |
nosql_injection | $ne/$gt/$regex/$where 操作符、认证绕过 |
ldap_injection | |
xpath_injection | 1=1、` |
jndi_injection | ${jndi:ldap://、${lower:j} 混淆、${env:} 环境变量查找 |
ssi_injection | <!--#exec cmd=、<!--#include file=、<!--#echo var= |
graphql_injection | __schema/__type、深度嵌套 DoS、mutation 检测 |
ssti | {{}}、FreeMarker ${}、ERB <% %>、Python MRO 遍历 |
协议与请求攻击
ssrf | |
xxe | <!ENTITY SYSTEM/PUBLIC、参数实体、DOCTYPE 声明 |
header_injection | %0d%0a / \r\n)、Set-Cookie/Location/Content-Length 注入 |
host_header | X-Forwarded-Host/X-Original-URL 投毒 |
request_smuggling | |
open_redirect | //evil.com 协议相对 URL、javascript:/data: 伪协议 |
cors | Origin: null、Access-Control-Allow-* 头注入、preflight 投毒 |
websocket | |
dns_rebinding |
HTTP 协议层校验
http_method | |
body_size | |
content_type | |
csrf_origin | |
ip_blacklist |
数据与序列化攻击
deserialization | O:数字: / C:数字: 序列化对象、unserialize() 调用、魔术方法引用 |
csv_injection | |
mail_header | |
jwt_attack | alg: none 绕过、kid 路径遍历注入、空签名检测 |
prototype_pollution | __proto__/constructor 键检测、__defineGetter__/__defineSetter__ |
文件与敏感数据
path_traversal | ..//..\\、php://filter/php://input、null 字节、URL 编码绕过 |
upload | <?php, <?=) 内容扫描 |
data_leak | -----BEGIN、数据库连接串、API Token、JWT Secret |
安装
composer require erikwang2013/security-php要求 PHP >= 8.1。
使用说明
快速开始(全局函数)
<?phprequire'vendor/autoload.php';// 扫描当前请求(自动提取 GET/POST/COOKIE/FILES)$threats = security_scan_current_request();if (!empty($threats)) {foreach ($threats as $threat) {echo"检测到攻击: {$threat->type} - {$threat->detail}\n"; }}// 或一行:安全检测 + 自动拦截security_guard();Laravel
安装后自动发现。手动发布配置:
php artisan vendor:publish --tag=security-config中间件别名 security 已自动注册,在路由中使用:
Route::middleware('security')->group(function(){ Route::post('/api', [ApiController::class, 'handle']);});或在 app/Http/Kernel.php 中注册全局中间件:
protected $middleware = [ \Erikwang2013\Security\Middleware\Laravel\SecurityMiddleware::class,];Webman
手动发布配置(将默认配置复制到 Webman 插件目录):
cp vendor/erikwang2013/security-php/config/security.php config/plugin/erikwang2013/security-php/app.php按需修改 config/plugin/erikwang2013/security-php/app.php,然后在 config/middleware.php 中添加:
return [ \Erikwang2013\Security\Middleware\Webman\SecurityMiddleware::class,];ThinkPHP
手动发布配置:
cp vendor/erikwang2013/security-php/config/security.php config/security.php按需修改 config/security.php,然后在 app/middleware.php 中添加:
return [ \Erikwang2013\Security\Middleware\Thinkphp\SecurityMiddleware::class,];Hyperf
手动发布配置:
cp vendor/erikwang2013/security-php/config/security.php config/autoload/security.php按需修改 config/autoload/security.php,然后在 config/autoload/middlewares.php 中添加:
return ['http' => [ \Erikwang2013\Security\Middleware\Hyperf\SecurityMiddleware::class, ],];手动调用
useErikwang2013\Security\SecurityGuard;// 初始化$config = require'config/security.php';SecurityGuard::init($config);// 扫描任意数据$threats = SecurityGuard::guard(['input' => '<script>alert(1)</script>']);// 检查是否需要拦截if (!empty($threats) && SecurityGuard::shouldBlock($threats)) { http_response_code(SecurityGuard::blockStatusCode());die(SecurityGuard::blockMessage());}配置说明
配置文件发布后位于 config/security.php,所有配置项均有中文注释。
总开关
'enabled' => true, // false 时关闭所有检测检测器配置
每个检测器独立控制:
'detectors' => ['xss' => ['enabled' => true, // 是否启用'mode' => 'block', // 'block' 拦截 | 'log' 仅记录 ],// ...],注意:
header_injection、ssti、nosql_injection默认为log模式,防止对正常文本(多段落文本、前端模板、Shell 变量)误拦截。确认业务场景后可按需改为block。
拦截配置
'block_status_code' => 403, // 默认 HTTP 状态码。当检测器返回自定义状态码时(如 405/413/415),// SecurityGuard::blockStatusCode($threats) 优先使用检测器的状态码'block_message' => 'Request blocked by security policy',日志配置
'log' => ['enabled' => true,'channel' => 'file','path' => '', // 留空使用临时目录'max_size' => 10, // MB,超过后自动轮转。设为 0 禁用'dedup_seconds' => 5, // 去重窗口,同一请求内相同攻击不重复记录],日志格式:
[2026-05-21 14:22:32] 192.168.1.1 POST /api/login | sql_injection | critical | field=username payload=admin'-- detail=SQL comment terminationIP 白名单
'whitelist_ips' => ['127.0.0.1', // 单个 IP'10.0.0.0/8', // CIDR 网段'192.168.1.0/24', // /24 子网'::1', // IPv6 单地址'fe80::/10', // IPv6 CIDR],字段白名单
'whitelist_fields' => ['_token', '_method', 'csrf_token'],IP 攻击升级黑名单
'ip_blacklist' => ['enabled' => true,'max_attempts' => 5, // 窗口内最大攻击次数'window_seconds' => 60, // 计数窗口(秒),超过后重置'ban_duration_seconds' => 900, // 封禁时长(秒),默认 15 分钟],当同一 IP 在 window_seconds 秒内触发 max_attempts 次任意攻击检测后,该 IP 被封禁 ban_duration_seconds 秒。封禁期间所有请求直接返回 403。
存储配置
'storage' => ['type' => 'file', // 'file' | 'redis' | 'cache'// File 存储(默认,零依赖)'file' => ['path' => ''],// Redis 存储(type=redis 时,需在外部创建 \Redis 实例后通过 redis_instance 传入)// 框架用户请使用框架自身的 Redis 连接方式(如 Laravel 的 Redis::connection())// 非框架用户请使用 php-redis 扩展创建:new \Redis(); $redis->connect('127.0.0.1', 6379);'redis' => ['prefix' => 'security:', ],// Cache 文件缓存(每个 key 独立文件,适合高并发读写)'cache' => ['path' => '','prefix' => 'security_', ],],file 模式将数据存储在单个 JSON 文件中(flock 原子写入)。redis 使用外部传入的 Redis 实例实现分布式共享存储。cache 将每个 key 存为独立文件,避免单文件写入竞争。
设计说明
架构
HTTP Request │ ▼┌─────────────────┐│ Middleware Layer │ 从框架 Request 提取 GET/POST/COOKIE/FILES → 扁平化 key-value│ (4 adapters) │ 调用 SecurityGuard::guard()└────────┬────────┘ │ ▼┌─────────────────┐│ SecurityGuard │ 入口门面:IP 白名单 → IP 黑名单检查 → 字段白名单 → 嵌套扁平化 → 正则超时保护 → 扫描│ │ 攻击记录:扫描后若发现威胁,自动记录 IP 到 IpBlacklist└────────┬────────┘ │ ┌────┴────┐ ▼ ▼┌────────┐ ┌──────────────┐│IpBlacklist│ │ DetectorChain │ 优先级排序 → 执行所有检测器 → 收集全部匹配(不再仅返回首个匹配)│ │ └──────┬───────┘│ ┌────┐ │ ││ │Storage││ ││ │File/ ││ ││ │Redis/││ ││ │Cache ││ │└──┴────┴─┘ │ ▼ ┌─────────────────┐ │ 31 Detectors │ 23 个继承 AbstractRegexDetector,仅定义 name() + patterns() + priority() │ (strategy) │ 8 个自定义 detect():Upload(文件内容扫描)、 │ │ JwtAttack(JWT 头解码)、PrototypePollution(键名检查)、 │ │ HttpMethod/BodySize/ContentType/CsrfOrigin(通过 $data 解耦 $_SERVER) └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Logger │ 攻击日志:fopen+flock 原子写入、按大小轮转、CRLF 注入防护、去重 └─────────────────┘关键设计决策
1. 抽象检测器基类
31 个检测器中的 23 个继承 AbstractRegexDetector,每个仅需定义 name() 和 patterns() 方法(约 15 行代码)。消除了 ~500 行重复的扫描循环代码。修改扫描逻辑(如新增嵌套数组支持)只需改动基类一处。
其余 8 个检测器直接实现 DetectorInterface 并自定义 detect() 方法:UploadDetector(文件扩展名+内容扫描)、JwtAttackDetector(JWT 结构解码分析)、PrototypePollutionDetector(对象键名检查)、HttpMethodDetector / BodySizeDetector / ContentTypeDetector / CsrfOriginDetector($_SERVER 超全局变量检查)。
classXssDetectorextendsAbstractRegexDetector{publicfunctionname(): string{ return'xss'; }protectedfunctionpatterns(): array{return ['/<script\b/i' => ['severity' => 'critical', 'detail' => 'Script tag injection'],'/\bon[a-z]+\s*=/i' => ['severity' => 'high', 'detail' => 'Event handler injection'],// ... ]; }}2. 嵌套数组扁平化
SecurityGuard::flattenData() 递归处理 JSON 请求体中的嵌套结构:
['user' => ['name' => '<script>x</script>']]→ ['user.name' => '<script>x</script>']数组值会被 JSON 编码为字符串供检测器扫描。字段名使用点号分隔路径(如 user.profile.bio)。
3. 安全措施
pcre.backtrack_limit=1000000,finally 中恢复 | ||
preg_match === falseerror_log | ||
\r\n\\r\\n,` | ||
AKIAIOS***XAMPLE | ||
4. 可插拔存储抽象
IpBlacklist 通过 StorageInterface 与持久化层解耦。SecurityGuard::createStorage() 工厂根据 storage.type 配置创建对应适配器注入:
interfaceStorageInterface{ get(string $key): mixed; set(string $key, mixed $value): void; delete(string $key): void; has(string $key): bool; all(): array; clear(): void;}FileStorage | flock | |
RedisStorage | ||
CacheStorage |
5. 框架适配策略
中间件层唯一职责:从框架 Request 提取数据 → 调用 SecurityGuard 核心检测逻辑与框架零耦合,仅依赖 PHP 8.1 标准库 Laravel 通过 extra.laravel.providers自动发现Webman/ThinkPHP/Hyperf 手动在中间件配置中注册 全局函数 security_guard()支持无框架项目
6. 扩展新检测器
// 方式一:正则匹配检测器(继承 AbstractRegexDetector)// 1. 创建 src/Detector/MyDetector.phpclassMyDetectorextendsAbstractRegexDetector{publicfunctionname(): string{ return'my_detector'; }protectedfunctionpatterns(): array{return ['/attack_pattern/i' => ['severity' => 'high', 'detail' => 'My attack description'], ]; }}// 方式二:自定义逻辑检测器(实现 DetectorInterface)// 适用于检查 $_SERVER、文件系统等非输入数据的场景classMyCustomDetectorimplementsDetectorInterface{publicfunctionname(): string{ return'my_custom'; }publicfunctiondetect(array $data): ?ThreatResult{// 自定义检测逻辑,可返回自定义 HTTP 状态码returnnew ThreatResult( type: 'my_custom', severity: 'high', field: '_server.SOME_VAR', payload: $_SERVER['SOME_VAR'] ?? '', detail: 'Custom attack detected', httpStatus: 418, // 自定义状态码 ); }}// 2. 在 SecurityGuard::$detectorMap 中注册'my_detector' => Detector\MyDetector::class,'my_custom' => Detector\MyCustomDetector::class,// 3. 在 config/security.php 中添加配置'my_detector' => ['enabled' => true, 'mode' => 'block'],'my_custom' => ['enabled' => true, 'mode' => 'block'],依赖
PHP >= 8.1 零外部依赖
测试
composer installvendor/bin/phpunitOK (192 tests, 578 assertions)感谢大家阅读,个人观点仅供参考,欢迎在评论区发表不同观点。
欢迎关注、分享、点赞、收藏、在看,我是微信公众号「PHP驿站」作者小皮。
夜雨聆风