本文目录导读:

- 方法一:纯 PHP 代码级防护(最简单,适合小型项目)
- 方法二:使用成熟的开源 PHP WAF(推荐,功能全)
- 方法三:基础设施级别 WAF(最全面,但涉及运维)
- 方法四:框架内的安全中间件(适合现代 PHP 框架)
- 关键补充:PHP 安全核心原则(比 WAF 更重要)
- 总结建议
PHP 实现 Web 应用防火墙(WAF)通常有 应用层 WAF 和 代理层 WAF 两种模式,对于 PHP 最常见的是在 PHP 代码层面进行拦截。
以下是在 PHP 中构建或配置 WAF 的几种主流方法,从轻量级代码到基础设施级:
纯 PHP 代码级防护(最简单,适合小型项目)
在 PHP 的入口文件(如 index.php)或公共的 init.php 中,加入防护代码,拦截常见的攻击特征。
核心拦截逻辑示例
<?php
// waf.php - 放置在项目根目录并引入
class SimpleWAF {
private static $rules = [
'sql_injection' => '/(\bSELECT\b|\bUNION\b|\bINSERT\b|\bOR\s+1=1\b|--|#)/i',
'xss' => '/(<script|javascript:|onerror=|onload=|<iframe|alert\()/i',
'path_traversal' => '/(\.\.\/|\.\.\\\\)/',
'rce' => '/(\bphpinfo\b|\beval\b|\bexec\b|\bshell_exec\b|\bsystem\b)/i',
];
public static function detect() {
foreach ($_GET as $key => $value) {
self::check($key, $value);
}
foreach ($_POST as $key => $value) {
self::check($key, $value);
}
foreach ($_COOKIE as $key => $value) {
self::check($key, $value);
}
}
private static function check($key, $value) {
if (is_array($value)) {
// 递归检查数组
foreach ($value as $k => $v) {
self::check($key . '[' . $k . ']', $v);
}
return;
}
foreach (self::$rules as $type => $pattern) {
if (preg_match($pattern, $value)) {
// 记录日志
error_log("[WAF] 拦截类型: {$type}, 参数: {$key}, 值: " . substr($value, 0, 200));
// 响应拦截(可自定义 403 页面)
http_response_code(403);
exit('<h1>403 Forbidden - 请求被安全策略拦截</h1>');
}
}
}
}
// 在入口文件调用
\SimpleWAF::detect();
注意事项
- 误杀率:正则匹配容易误杀正常业务(如用户输入了
<b>加粗标签),需要定期调整白名单规则。 - 效率:每次请求都进行正则匹配会增加约
1ms - 1ms的开销,建议使用opcache。 - 绕过风险:严格依赖正则,容易被编码绕过(如 URL 编码
%27或 Unicode 编码)。
使用成熟的开源 PHP WAF(推荐,功能全)
不要重复造轮子,推荐使用社区成熟方案,它们对绕过规则的研究更深入。
PHP IDS(PHP Intrusion Detection System)
- 特点:通过
phpids规则库检测恶意输入。 - 集成方式:Composer 安装或直接引入。
composer require phpids/phpids
- 配置简单,可以生成详细的日志,但该项目近年来维护不频繁。
基于 Composer 的轻量级组件(如 akka/php-waf)
这类包提供现成的中间件式过滤,适合配合 Laravel、ThinkPHP 使用。
自定义规则引擎
如果预算允许,可以购买商业 WAF 的 PHP SDK(如 阿里云、腾讯云 提供的 SDK),将请求转发给自己的审核接口。
基础设施级别 WAF(最全面,但涉及运维)
虽然你在问“PHP 怎么实现”,但最有效率的 WAF 往往不在 PHP 层,而是在 PHP 之前。
基于 Nginx + Lua(OpenResty)的 WAF
- 原理:在
Nginx请求处理阶段,用 Lua 脚本分析请求体(GET/POST),流量不进入 PHP 就拦截。 - 代表项目:
lua-resty-waf。 - 优势:性能极高,不影响 PHP 业务代码,可以针对 IP、User-Agent 做限流。
云 WAF(如 Cloudflare / 阿里云盾 / 腾讯云 WAF)
- 原理:DNS 解析指向云 WAF 节点,云端过滤后回源到你的 PHP 服务器。
- 优势:无需修改 PHP 代码,防护规则实时更新,能防 DDoS(分布式拒绝服务攻击)。
框架内的安全中间件(适合现代 PHP 框架)
如果你使用 Laravel / Symfony / ThinkPHP,建议使用框架自带的安全机制,这实际上是原理最简单、最稳定的“业务级 WAF”。
Laravel 示例
Laravel 有 中间件 机制,官方强烈建议使用 ValidateRequests 和 TrustProxies。
自定义一个防 SQL 注入中间件:
php artisan make:middleware SqlInjectionFilter
public function handle($request, Closure $next) {
$input = $request->all();
array_walk_recursive($input, function(&$value) {
// 过滤危险字符,转为安全的 HTML 实体,或直接拒绝
$value = preg_replace('/(\bSELECT\b.*\bFROM\b)/i', '', $value);
});
$request->merge($input);
return $next($request);
}
但更推荐的是使用:
- Laravel Validation:严格校验参数类型(
integer|min:1),SQL 注入和 XSS 通常源于未校验的字符串。 - Eloquent ORM:它使用 PDO 预处理语句,这是防御 SQL 注入的最根本手段,PHP 强制要求针对数据库操作使用绑定参数。
关键补充:PHP 安全核心原则(比 WAF 更重要)
在构建任何 WAF 插件之前,务必确认以下原则已落实,否则 WAF 形同虚设:
-
SQL 注入防御:永不拼接 SQL 字符串,必须使用
PDO::prepare()或mysqli_prepare()绑定参数。$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?'); $stmt->execute([$_GET['id']]); -
XSS 防御:输出时对字符串进行 HTML 转义。
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
-
文件上传安全:校验文件头(MIME 类型)、使用随机文件名、禁止可执行目录。
总结建议
| 场景 | 推荐方案 |
|---|---|
| 个人小型项目 / 学习 | 方法一:PHP 正则+简单规则,快速搭建 |
| 公司生产环境 | 方法二:Composer 引入成熟包 + 定期更新规则 |
| 大型系统 / 高并发 | 方法三:Nginx WAF / 云 WAF(这样 PHP 层无需耗性能) |
| 任何项目 | 必须:预处理 SQL + 编码输出(从根上消灭漏洞) |
最核心的忠告:WAF 只是最后的防线,如果你使用了 PDO 预处理和 htmlspecialchars,你的 PHP 代码已经比 90% 的“WAF 插件”更安全了,不要把 WAF 当成不写安全代码的借口。