userfrosting / fortress
一个用于根据 JSON Schema 白名单、验证和规范 HTTP 请求数据的 PHP 库
Requires
- php: >=7.1
- ezyang/htmlpurifier: ^4.7.0
- userfrosting/i18n: ~4.5.0
- vlucas/valitron: ^1.2.3
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.13
- phpunit/phpunit: ^7.5 | ^8.5
README
分支 | 构建 | 覆盖率 | 风格 |
---|---|---|---|
master | |||
develop | |
如果您只是想表明您喜欢这个项目,或者想稍后记住它,您应该 星标,而不是 分支,此仓库。分支操作仅适用于您准备创建代码的副本以进行工作时。
由 Alex Weissman 编写
版权(c)2015-2019
一个以规则集为驱动,优雅地在客户端和服务器端进行白名单、转换和验证用户输入的系统。
简介
外部世界的数据是现代交互式网络服务和应用的阿基里斯之踵。当网络应用接受其不应接受的用户输入或未能中和输入中的有害部分时,代码注入、跨站脚本(XSS)、CSRF 以及许多其他类型的恶意攻击就会成功。即使是非恶意用户也可能无意中提交一些会破坏您的网络服务的内容,导致其以某些意想不到的方式运行。
为了安全和优质的用户体验,对于网络开发者来说,做两件事很重要
- 确定您的应用程序应接受哪种类型的输入,以及;
- 确定当您的应用程序接收到违反这些规则的内容时,应该如何表现。
听起来很简单,对吧?不幸的是,即使是经验丰富的开发者也常常出错,允许恶意用户在应用程序的服务器上执行 SQL 或 PHP(在 XSS 和 CSRF 攻击的情况下,允许用户欺骗 其他用户 执行恶意代码)。
问题的一部分在于,这种类型的过滤必须在用户可以向服务器提交原始数据的每个应用点进行。一个现代网络应用可能接受数百种不同的 POST 请求,手动为每个请求编写规则可能变得极其繁琐。其中大部分工作必须在客户端(为了用户体验)和服务器端(为了安全性)进行。
Fortress 通过提供一套统一的规则,在客户端(JavaScript)和服务器端(PHP)对原始用户输入进行验证,从而解决了这个问题。您只需创建一个 请求模式,该模式定义了您期望用户提交的字段以及如何处理这些字段的 规则。例如,您可能想检查电子邮件地址是否格式正确。请求模式,一个简单的 YAML 或 JSON 文档,使得在一个地方操作这些规则变得容易。
请求模式可以在服务器端应用于接收到的请求数据,也可以转换为与客户端验证库兼容的格式,例如 jQuery 验证插件,这使得在无需编写每个规则两次的情况下,可以轻松进行客户端和服务器端验证。
一个示例请求模式,使用 WDVSS 标准 编写
schema.yaml
name:
validators:
length:
min: 1
max: 200
message: Please enter a name between 1 and 200 characters.
required :
message : Please specify your name.
email:
validators:
required:
message: Please specify your email address.
length:
min: 1
max: 150
message: Please enter an email address between 1 and 150 characters.
email:
message : That does not appear to be a valid email address.
message:
validators:
required:
message: Please enter a message
依赖项
- PHP 5.6+
- Valitron(服务器端验证)
- HTML Purifier
- Symfony YAML 解析器
- userfrosting/i18n
- userfrosting/support
安装
使用 Composer 安装
- 如果您尚未安装,请获取 Composer 并 安装它 - 最好是在全局范围内。
- 要求使用 Fortress,可以通过运行
php composer.phar require alexweissman/fortress
,或者创建一个composer.json
文件
{
"require": {
"php": ">=5.6.0",
"userfrosting/fortress": "^4.2.0"
}
}
然后运行 composer install
。
- 在您的项目中包含
vendor/autoload.php
文件
require dirname(__DIR__) . '/vendor/autoload.php';
用法
请求模式
要读取 YAML 或 JSON 模式,请使用 YamlFileLoader
$loader = new \UserFrosting\Support\Repository\Loader\YamlFileLoader('schema/forms/contact.yaml');
要使用它,必须将其读取并加载到 RequestSchemaRepository
对象中
$schema = new \UserFrosting\Fortress\RequestSchema\RequestSchemaRepository($loader->load());
如果您愿意,可以在运行时向模式添加额外的验证规则
$schema->addValidator("puppies", "required");
$schema->addValidator("minions", "range", [
"min" => 0,
"max" => 20,
"message" => "Not enough minions"
]);
$schema->addValidator("email", "length", [
"min" => 1,
"max" => 100,
"message" => "ACCOUNT_EMAIL_CHAR_LIMIT"
]);
数据转换
数据转换器执行以下任务
- 将输入数组与模式进行白名单检查。默认情况下,模式中未列出的任何参数将被过滤掉。其他选项是 "error" 和 "skip"。
- 对输入数据进行一系列转换。例如,
trim
或purify
。 - 为模式中不存在于输入数组的字段设置任何默认值。
$post = [
"puppies" => "<script>I'm definitely really a puppy </script>0 ",
"horses" => "seven pretty horses"
];
$transformer = new \UserFrosting\Fortress\RequestDataTransformer($schema);
// Transform, and print transformed data for demo purposes
$transformedData = $transformer->transform($post, "skip");
echo "<h2>Transformed data</h2>";
echo "<pre>";
print_r($transformedData);
echo "</pre>";
服务器端数据验证
要处理用户输入的数组,请使用模式和翻译对象创建一个 ServerSideValidator
对象。
翻译对象
Fortress 需要一个 Translator
对象(见 i18n),用于翻译可能出现在规则中的消息键
$locale = new \UserFrosting\I18n\Locale('en_US');
$dictionary = new \UserFrosting\I18n\Dictionary($locale, $this->ci->locator);
$translator = new \UserFrosting\I18n\Translator($dictionary);
然后,在输入数组上调用 validate
。如果任何规则失败,则 validate
将返回 false。调用 errors
以获取生成的错误消息列表。您可能想要将这些错误消息存储到闪存消息系统中,以便将它们显示给用户。
$validator = new \UserFrosting\Fortress\ServerSideValidator($schema, $translator);
if (!$validator->validate($transformedData)) {
echo "<h2>Validation results</h2>";
echo "<pre>";
print_r($validator->errors());
echo "</pre>";
}
客户端数据验证
当生成页面或表单时,您将使用 Adapter
类之一从您的 WDVSS 模式生成兼容的规则集
// Test client validators
$clientVal = new \UserFrosting\Fortress\Adapter\JqueryValidationAdapter($schema, $translator);
echo "<h2>Client-side validation schema (JSON)</h2>";
echo "<pre>";
print_r($clientVal->rules());
echo "</pre>";
添加命名空间到验证字段名
您还可以向字段名添加数组前缀,以生成针对输入模式的验证规则,这些规则将使用为生成验证规则的那个表单的命名空间包装所有字段名。
// Test client validators
$clientVal = new \UserFrosting\Fortress\Adapter\JqueryValidationAdapter($schema, $translator);
echo "<h2>Client-side validation schema (JSON)</h2>";
echo "<pre>";
print_r($clientVal->rules('json',false,'mycoolform1'));
echo "</pre>";
这将生成具有字段名的验证规则 mycoolform1[<fieldname>] : { .... }
而不是 <fieldname> : { .... }
当您在同一个页面上为多个表单或表单部分生成验证规则时,这很有用
消息键
规则的 message
可以是一个纯字符串,或者一个 可翻译的消息键。
在可翻译消息键的定义中,关键字 "self" 是保留的,用于引用正在验证的字段名称。因此,这样的消息
"MIN_LENGTH" => "The field '{{self}}' must be at least {{min}} characters long"
对于一个定义为
tagline:
validators:
length:
min: 10
message: MIN_LENGTH
的字段
将翻译为
"The field 'tagline' must be at least 10 characters long"
将规则限制为仅服务器或客户端
有时,您可能只想将验证规则应用于服务器端,而不是在客户端的 JavaScript 中,或者反之亦然。例如,可能有一些包含需要服务器端验证的隐藏数据的表单,但这些数据不会在浏览器中直接由用户操作。因此,这些字段不需要客户端验证规则。
为了实现这一点,每个验证规则现在可以接受一个 domain
属性。设置为 "server" 将仅在服务器端应用。设置为 "client" 将仅在客户端规则中显示。如果没有指定,则默认在服务器端和客户端应用规则。您还可以使用值 "both" 显式设置此属性。