alexweissman / fortress
一个用于对HTTP请求数据进行白名单、验证和规范化的PHP库,针对JSON Schema
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
一个基于模式驱动的系统,用于优雅地在客户端和服务器端对用户输入进行白名单、转换和验证,基于一组统一的规则。
简介
来自外部的数据是现代交互式Web服务和应用的阿喀琉斯之踵。当Web应用接受它不应接受的用户输入,或未能中和输入中的有害部分时,代码注入、跨站脚本(XSS)、CSRF等许多类型的恶意攻击就会成功。即使是非恶意用户也可能无意中提交一些会破坏您的Web服务的内容,导致它以某种意想不到的方式运行。
为了安全和优质的用户体验,Web开发者需要做两件事:
- 决定应用程序应接受的确切类型的输入;
- 决定当应用程序收到违反这些规则的内容时应该如何处理。
听起来很简单,对吧?不幸的是,即使是经验丰富的开发者也经常犯错,允许恶意用户在应用程序的服务器上执行SQL或PHP(或者在XSS和CSRF攻击的情况下,允许用户欺骗其他用户执行恶意代码)。
问题的部分原因在于,这种过滤必须在用户可以向服务器提交原始数据的每个应用点进行。现代Web应用可能接受数百种不同的POST请求,手动编写每个请求的规则可能变得非常繁琐。其中大部分工作也必须在客户端(为了用户体验)和服务器端(为了安全)进行。
Fortress通过提供一个统一的接口,使用单一统一的规则集在客户端(在JavaScript中)和服务器端(在PHP中)验证原始用户输入,从而解决了这个问题。您只需创建一个 请求模式,该模式定义了您期望用户提交的字段以及如何处理这些字段的内容的 规则。例如,您可能想检查电子邮件地址是否格式正确。请求模式(简单地是一个YAML或JSON文档)使得在单个位置操纵这些规则变得容易。
请求模式可以在服务器端应用于接收到的请求数据,也可以转换为与客户端验证库兼容的格式,例如 jQuery Validation插件,这使得执行客户端和服务器端验证变得容易,而无需将每个规则编写两次。
使用 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净化器
- 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"明确设置此属性。