从Yii2的Request看其CSRF防范策略
2015-06-08 01:16
681 查看
先画一幅流程图理理思路:
1. 问题是这样的:
今天在处理一个这样的需求, 在app\controllers\LoginController.php中定义了
index方法来处理登录(主要是用于非Web页面登录,比如
Curl -X POST http://api/login[/code]):
结果呢, 无论是用测试工具POSTMAN还是用命令行CURL请求总是会得到http400:Bad Request的错误;而如果用Web网页方式GET访问(去除verbFilter的POST限制),是正常的
通过帖子下面的帖子找到了问题的所在,是CSRF验证的原因;
因为Web网页访问的时候form表单中会有对应的一个隐藏input:_csrf进行了验证才可以正常进行访问;
而非网页访问方式(不通过Web表单)是无法通过csrf验证的。
而CURL访问方式都没有用到cookie, 故我认为没有必要在这里防范csrf攻击,暂时用下面的办法将其禁用。class Controller extends \yii\base\Controller { /** * @var boolean whether to enable CSRF validation for the actions in this controller. * CSRF validation is enabled only when both this property and [[Request::enableCsrfValidation]] are true. */ public $enableCsrfValidation = false; <- set this to false2. 趁机来研究下 Yii2 的 CSRF 防范机制
什么是 CSRF 攻击?
简单说,攻击者盗用了你的身份,以你的名义发送恶意请求。
最有效地一个方法原理是这样的:Cookie Hashing, 让服务器发送给客户端的所有表单中都标示一个随机值
_csrf,并同时在客户端的COOKIE中保存一个相关联的token;验证的时候,服务端每次对接收到的请求
_POST()过来的一个input hidden _csrf跟客户端的COOKIE中的token进行对照验证攻击者攻击的原理是利用了客户端的COOKIE,但是攻击者是得不到COOKIE具体的内容的,他只是
这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了:>利用(这里抛开XSS攻击的可能性,由于用户的Cookie很容易由于网站的XSS漏洞而被盗取,这就另外的1%。一般的攻击者看到有需要算Hash值,基本都会放弃了);所以攻击者没法在攻击URL中加入token,这样就无法通过验证。
来看看:Yii2是不是这么干的。3. 从外到内探究
Yii文档中有这么一段话是对其CSRF防范机制的概述:* When CSRF validation is enabled, forms submitted to an Yii Web application must be originated * from the same application. If not, a 400 HTTP exception will be raised. * * Note, this feature requires that the user client accepts cookie. Also, to use this feature, * forms submitted via POST method must contain a hidden input whose name is specified by [[csrfParam]]. * You may use [[\yii\helpers\Html::beginForm()]] to generate his hidden input. * * In JavaScript, you may get the values of [[csrfParam]] and [[csrfToken]] via `yii.getCsrfParam()` and * `yii.getCsrfToken()`, respectively. The [[\yii\web\YiiAsset]] asset must be registered. * You also need to include CSRF meta tags in your pages by using [[\yii\helpers\Html::csrfMetaTags()]]3.1 先看看浏览器中的CSRF都有哪些体现:
在第一张图片中,很明显,<meta>和<form>中分别有一个 csrf_token,并且是一致的
在第二章图片中,cookies['_csrf']中也有一个更长的串串,这个是。。。?
经过一番研究,这个长长的串是因为Yii默认开启了cookieValidation禁用
在 config文件中禁用:enableCookieValidation让分析CSRF的过程变得简单'components' => [ 'request' => [ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation 'cookieValidationKey' => '83r5HbITBiMfmiYPOZFdL-raVp4O1VV4', 'enableCookieValidation' => false, 'enableCsrfValidation' => true, ]来对比下禁用之前和之后的区别:
这样 _csrf 就简单多了,当然这是不安全的3.2 从
view开始寻找csrf3.2.1 先找找表单里的 app\views\site\login.php
没有找到csrf的定义,那应该是封装到ActiveForm了3.2.2 vendor\yiisoft\yii2\widgets\ActiveForm.php
class ActiveForm extends yii\base\Widget { public function init() { ... echo yii\helpers\Html::beginForm(...); } public function run() { ... echo yii\helpers\Html::endForm(...); } }3.2.3 yii\helpers\Html
终于找到了CSRFpublic static function beginForm($action = '', $method = 'post', $options = []) { $action = Url::to($action); $hiddenInputs = []; $request = Yii::$app->getRequest(); if ($request->enableCsrfValidation && !strcasecmp($method, 'post')) { $hiddenInputs[] = static::hiddenInput($request->csrfParam, $request->getCsrfToken()); } ... ...3.2.4 去
app\views\layouts\main.php看看里面的CSRF是怎么来的<head> <meta charset="<?= Yii::$app->charset ?>"/> <meta name="viewport" content="width=device-width, initial-scale=1"> <?= Html::csrfMetaTags() ?> <title><?= Html::encode($this->title) ?></title> <?php $this->head() ?> </head>
[/code]
正好也是在3.2.3 yii\helpers\Html中定义的/** * Generates the meta tags containing CSRF token information. * @return string the generated meta tags * @see Request::enableCsrfValidation */ public static function csrfMetaTags() { $request = Yii::$app->getRequest(); if ($request instanceof Request && $request->enableCsrfValidation) { return static::tag('meta', '', ['name' => 'csrf-param', 'content' => $request->csrfParam]) . "\n " . static::tag('meta', '', ['name' => 'csrf-token', 'content' => $request->getCsrfToken()]) . "\n"; } else { return ''; } }3.2.5 原来csrf都是由
head中Yii::$app->request处理的$request->getCsrfToken()
form中$request->csrfParam $request->getCsrfToken()
看来 整个验证的流程都是由getCsrfToken()触发的。3.3 研究源码
源码请参考:http://www.yiiframework.com/doc-2.0/yii-web-request.html
来个流程图(手绘版):
相关文章推荐
- Yii2为ActiveForm的widget组件设置属性
- Yii2中的OAuth扩展及QQ互联登录
- Yii2 Unable to verify your data submission.
- Yii2 使用Ajax自动获取表单数据
- Yii2 DropDownList用法
- Yii 2发送带附件的邮件
- Yii2上传文件
- Yii2 实现上下联动的下拉框
- Yii2同时搜索多个字段
- Yii2让关联字段支持搜索功能
- Yii2中多表关联查询(hasOne、hasMany、join、joinwith)
- Yii2关联查询用法
- Yii2基本的访问控制AccessControl的一些理解
- Yii获取当前url和域名的方法
- php查询whois信息的方法
- php实现有趣的人品测试程序实例
- 浅谈PHP中Stream(流)
- php判断用户是否手机访问代码
- 使用PhpStorm开发PHP环境搭建
- OS X Yosemite 10.10. 自带PHP环境gd库扩展缺少freetype 解决办法