patchstack / engine-php
Patchstack 的防火墙引擎。
Requires
- php: >=5.6
Requires (Dev)
- phpunit/phpunit: ^9.5
README
此存储库包含 Patchstack 的防火墙引擎。它可以在其他内容管理系统内部实现,以提供防火墙功能。
实现
实现简单,示例可以在 /tests/FirewallTest.php
中查看
示例防火墙规则可以在 /tests/data/Rules.json
中查看
示例白名单规则可以在 /tests/data/Whitelist.json
中查看
use Patchstack\Processor; use Patchstack\Extensions\WordPress\Extension; // Load the firewall rules, whitelist rules and settings from some place. $firewallRules = []; $whitelistRules = []; $settings = []; // Setup the firewall rules processor. $firewall = new Processor( new Extension(), $firewallRules, $whitelistRules, $settings ); // And launch it. If a request was a hit with a firewall rule, it will automatically stop execution. $firewall->launch();
功能
此防火墙引擎可以解析和理解基于 JSON 的防火墙规则。这些基于 JSON 的防火墙规则允许您匹配参数、匹配多个条件为真、对有效负载应用突变(例如,JSON 解码或 base64 解码)并与 PHP 函数的输出进行比较。
例如,为了防止 SQL 注入,而不必编写正则表达式来确定某个 GET(查询参数)变量是否为数字,我们可以简单地创建包含以下 JSON 规则的防火墙规则。
[ { "parameter":"get.pid", "match":{ "type":"ctype_digit", "value":false } } ]
在这种情况下,防火墙规则将检查 URL 中是否设置了查询参数 pid,并且如果 PHP 的 ctype_digit 函数对此参数的返回值为 false,将阻止请求。更多示例在本文档底部。
性能
当然,性能也是一个关注点,您不希望由于防火墙而显著减慢用户网站的速度。众所周知,许多防火墙插件由于代码未优化或防火墙引擎的奇怪功能而减慢了网站速度。我们也决定专注于新防火墙引擎的性能。例如,如果规则包含用于匹配的特定参数,我们首先确定该参数是否存在,然后再继续处理防火墙规则条件。
我们对防火墙引擎进行了测试,并提供了 100 个防火墙规则。当然,在没有任何现实场景下,网站需要处理这么多防火墙规则,但它可以给您一个性能影响的概念。
处理时间:PHP 5.6:0.0020,或约 2 毫秒;PHP 7.3:0.0013 秒,或约 1.3 毫秒;PHP 7.4:0.00017 秒,或约 0.17 毫秒;PHP 8+:0.00011 秒,或约 0.11 毫秒
这些数字可能会略有变化,因为我们仍在进行优化和调整。然而,与基于 PHP 代码的先前防火墙规则相比,它快了 10 倍。
扩展
新防火墙引擎的库允许您创建扩展来定义和覆盖某些函数的工作方式。该扩展要求您实现一些函数
- 匹配防火墙规则后请求的日志记录方式
- 谁可以绕过整个防火墙。例如,WordPress 的白名单用户角色
- 哪些类型的请求可以绕过整个防火墙。例如,请求中的某些关键词
- 确定访客是否在特定时间范围内因触发防火墙规则中的 X 次匹配而被阻止
- 如果请求被阻止,应该发生什么。(例如,显示阻止页面)
- 访客 IP 地址应该如何捕获(这可能在主机和环境中有很大差异)。必须妥善处理,否则访客可以通过 X-Forwarded-For 等头伪造 IP 地址并绕过某些限制。
- 如何确定当前请求是否为文件上传请求
您可以创建扩展来控制防火墙的一些功能如何交互和工作。
关注点
我们之前听到的一个潜在问题是,由于它是一个基于PHP的防火墙,并且集成在WordPress中,它会不会错过某些漏洞?这是可能的,但在几年之后,我们得出的结论是,这只会影响非常少数的漏洞。
我们必须在简单性(易于集成WordPress与需要对web服务器配置进行奇怪修改,如Apache的auto_prepend_file,这将大大增加负载,因为网站上的每一个请求都必须通过它)和覆盖率(在99%到99.9%之间)之间做出选择。通过WordPress的init钩子,并将钩子顺序设置为~PHP_INT_MAX(尽可能早),对于几乎所有漏洞都是足够的。
我应该和谁联系?
规则示例
以下是一些基于JSON的规则的更多示例,这些示例具有更复杂的条件。
与正则表达式相比,这类防火墙规则创建起来更容易、更快。当然,如上例所示,一条规则可以包含多个规则,这些规则通过不同的条件堆叠。
检查数组 ($_POST['usernames'][]) 是否包含给定数组中的任何值。
[ { "parameter":"post.usernames", "match":{ "type":"array_in_array", "value":[ "test", "admin" ] } } ]
检查值 ($_GET['user']) 是否不在数组中
[ { "parameter":"get.user", "match":{ "type":"not_in_array", "value":[ "admin" ] } } ]
检查URL是否匹配正则表达式
[ { "parameter":"server.REQUEST_URI", "match":{ "type":"regex", "value":"\/(\\\/something\\\/)\/msi" } } ]
检查值 ($_GET['id']) 是否不是数字或小于100
[ { "parameter":"get.pid", "match":{ "type":"ctype_digit", "value":false } }, { "parameter":"get.pid", "match":{ "type":"less_than", "value":100 } } ]
检查查询参数(test)是否存在于URL中
[ { "parameter":"get.test", "match":{ "type":"isset" } } ]
检查 $_POST['backdoor'] == mybackdoor 且 user-agent 包含 some_backdoor_agent
[ { "parameter":"post.backdoor", "match":{ "type":"equals", "value":"mybackdoor" }, "inclusive":true }, { "parameter":"server.HTTP_USER_AGENT", "match":{ "type":"contains", "value":"some_backdoor_agent" }, "inclusive":true } ]
检查 $_POST['payload'] 是否包含以 base64(json()) 编码的有效载荷,其中 user_role 键等于 administrator
[ { "parameter":"post.payload", "mutations":[ "base64_decode", "json_decode" ], "match":{ "type":"array_key_value", "key":"user_role", "match":{ "type":"equals", "value":"administrator" } } } ]
检查 $_GET['action'] 或 $_POST['action'] 是否包含值的一部分是值的数组的一部分,并且用户不是管理员
[ { "parameter":"rules", "rules":[ { "parameter":"get.action", "match":{ "type":"in_array", "value":[ "restaurant_system_customize_button", "restaurant_system_insert_dialog" ] } }, { "parameter":"post.action", "match":{ "type":"in_array", "value":[ "restaurant_system_customize_button", "restaurant_system_insert_dialog" ] } } ], "inclusive":true }, { "parameter":false, "match":{ "type":"current_user_cannot", "value":"administrator" }, "inclusive":true } ]
检查用户的IP地址是否在列表中(例如白名单)注意,server.ip 参数是一个特殊的计算属性,它通过附加到库的扩展检索IP地址。这个IP抓取功能可以根据您的需求进行调整。
[ { "parameter":"server.ip", "match":{ "type":"in_array", "value":[ "127.0.0.1" ] } } ]
检查特定值是否在请求中($_GET,$_POST,$_SERVER['REQUEST_URI'],原始POST数据)的任何地方存在
[ { "parameter":"all", "mutations":[ "getArrayValues" ], "match":{ "type":"regex", "value":"\/(\\\/something\\\/)\/msi" } } ]
检查上传的文件 ($_FILES['img']) 是否包含内容中的PHP打开标签
[ { "parameter":"files.img", "match":{ "type":"file_contains", "match":{ "type":"contains", "value":"<?php" } } } ]
检查 swp_debug 参数是否设置为 load_options,并且当前用户不是管理员。 https://patchstack.com/database/vulnerability/social-warfare/wordpress-social-warfare-plugin-3-5-2-unauthenticated-remote-code-execution-rce-vulnerability
[ { "parameter":"get.swp_debug", "match":{ "type":"equals", "value":"load_options" }, "inclusive":true }, { "parameter":false, "match":{ "type":"current_user_cannot", "value":"administrator" }, "inclusive":true } ]