PHP⾯试题精讲—从Yii2源码ActiveForm看如何安全处理表单验证⽇拱⼀卒⽆有尽,功不唐捐终⼊海
⽬录
⼀、问题:什么是安全的表单验证?
这个问题⼀般会作为⾯试题出现,因为PHP运⽤最⼴泛的还是web,那么对于web来讲,就会有表单处理数据。
那么,如何处理表单,也就成了⼀个难以避开的经典问题。
⼆、经典场景:⽤户登录
以最常见的⽤户登录表单来说,我们可以看到界⾯,基本为这种
在这个经典场景中,包含了
1. ⽤户名
2. 密码
3. 记住我
4. 提交按钮
其中⽤户名和密码⽤于校验⽤户⾝份,记住我⽤于浏览器保持⽤户登录状态,提交按钮⽤于最终的表单提交。
三、分析ActiveForm源码
为什么我们要选择分析ActiveForm的源码呢?
因为这是在页⾯构建form表单的组件,我们先从前端分析⼀个合格的表单都有哪些。
ActiveForm源码的位置在/vendor/yiisoft/yii2-bootstrap/src/ActiveForm.php
在页⾯的调⽤⽅式如下
<?php $form = ActiveForm::begin([
'id' => 'login-form',
'layout' => 'horizontal',
'fieldConfig' => [
'template' => "{label}\n<div class=\"col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
'labelOptions' => ['class' => 'col-lg-1 control-label'],
],
]); ?>
<?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= $form->field($model, 'rememberMe')->checkbox([
'template' => "<div class=\"col-lg-offset-1 col-lg-3\">{input} {label}</div>\n<div class=\"col-lg-8\">{error}</div>",
]) ?>
<div class="form-group">
<div class="col-lg-offset-1 col-lg-11">
<?= Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
通过ActiveForm::begin带的参数初始化表单,由于这是demo代码,所以没有改变默认配置,这⾥我们再回到源码,需要重点观察的有两个/**
* @var bool whether to enable client-side data validation.
* If [[ActiveField::enableClientValidation]] is set, its value will take precedence for that input field.
*/
public$enableClientValidation=true;
enableClientValidation客户端验证,也就是我们说的前端验证,表单在提交之前前端校验规则,如果不复合规则,就不会提交给后端,这样可以减少数据库压⼒。
默认调⽤的结果是,在页⾯最后输出校验表单的js
<script>jQuery(function($){
jQuery('#login-form').yiiActiveForm([{"id":"loginform-username","name":"username","container":".field-loginform-username","input":"#loginform-username"," error":".help-block.help-block-error","validate":function(attribute, value, messages, deferred, $form){quired(value, messages,{"message":" Username cannot be blank."});}},{"id":"loginform-password","name":"password","container":".field-loginform-password","input":"#loginform-password","error ":".help-block.help-block-error","validate":function(attribute, value, messages, deferred, $form){quired(value, messages,{"message":"Pass word cannot be blank."});}},{"id":"loginform-rememberme","name":"rememberMe","container":".field-loginform-rememberme","input":"#loginform-remember me","error":".help-block.help-block-error","validate":function(attribute, value, messages, deferred, $form){yii.validation.boolean(value, messages,{"trueVal ue":"1","falseValue":"0","message":
"Remember Me must be either \"1\" or \"0\".","skipOnEmpty":1});}}],[]);
});</script><
##2.enableAjaxValidation ajax验证
/**
* @var bool whether to enable AJAX-based data validation.
* If [[ActiveField::enableAjaxValidation]] is set, its value will take precedence for that input field.
*/
public$enableAjaxValidation=false;
enableAjaxValidation,ajax校验,即离开焦点之后触发ajax提交,交给后端校验规则并返回校验结果。这种⼀般在表单字段验证规则⽐较复杂的时候使⽤。
覆盖默认规则的⽅式就是在ActiveForm调⽤的时候写⼊配置数组中,下⾯就是启⽤了ajax校验的写法。
ActiveForm::begin(['options'=>['enableAjaxValidation'=>true]);
ajax的校验需要我们⼿动写逻辑接收并返回结果,⼀般的model层处理数据时,只需要类似下⾯这种就可以。
if(\Yii::$app->request->isAjax&&\Yii::$app->request->post()){
\Yii::$app->response->format=\yii\web\Response::FORMAT_JSON;
$model->load(\Yii::$app->request->post());jquery框架面试题
return\yii\bootstrap\ActiveForm::validate($model);
}
三、CSRF
什么是CSRF呢?
跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者XSRF, 是⼀种挟制⽤户在当前已登录的Web应⽤程序上执⾏⾮本意的操作的
攻击⽅法。跟跨⽹站脚本(XSS)相⽐,XSS 利⽤的是⽤户对指定⽹站的信任,CSRF 利⽤的是⽹站对⽤户⽹页浏览器的信任。
那么Yii2中是如何防范CSRF的呢?
默认的项⽬是开启CSRF的,⽐如经典的登录表单中,我们就能发现页⾯⽣成的csrf-token。
<meta name="csrf-token"content="4vUtwhUZY7dBvZQH3jWTze3B3sUNxFAC1jUA7V5Gu9-tmkWgZ3IHmimQzm2mROC1hqmHs0GSZlKJUlSeNRzOjA==" >
他会包含在请求中。
四、模型校验
当⽤户点击提交按钮,或者ajax验证规则的时候,框架就会使⽤模型的规则进⾏校验,由于model的验证规则不是本⽂的重点,所以这⾥不做⾮常详细的讲解。
/**
* @return array the validation rules.
*/
public function rules()
{
return[
// username and password are both required
[['username','password'],'required'],
// rememberMe must be a boolean value
['rememberMe','boolean'],
// password is validated by validatePassword()
['password','validatePassword'],
];
}
⼀般在实际开发中,由规则的简单到复杂⼀般的使⽤顺序是
1. rules()使⽤基本的规则,必选/数据类型/长度
2. scenario场景区分不同的验证规则
3. ⾃定义规则适应更多的验证场景
在模型的save()⽅法中,会默认调⽤validate()验证所有的规则,如果你不需要可以在调⽤的时候把第⼀个默认参数设置为fasle跳过验证。
五、评论区作业
输出是最好的输⼊,如果你对着⼩黄鸭都说不明⽩,怎么⼜能指望你能⾃⼰明⽩呢?
1. 原⽣PHP写法下如何防⽌SQL注⼊?
欢迎你在第⼀时间把思路写在评论区,最好不查资料。
六、总结
表单验证是⼀个⾮常经典的问题,在⾯试环节我们可以通过⾯试者回答问题是否全⾯看出来他是否对⽤户输⼊敏感。
希望各位可以反复看这部分内容,做到⾯试过程中不会遗漏。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论