您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
从Yii2的Request看其CSRF防范策略
 
作者:Ganiks 来源:博客园 发布于:2015-8-21
  3189  次浏览      25

先画一幅流程图理理思路:

1. 问题是这样的:

今天在处理一个这样的需求, 在 app\controllers\LoginController.php中定义了index方法来处理登录(主要是用于非Web页面登录,比如Curl -X POST http://api/login):

结果呢, 无论是用测试工具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 false

2. 趁机来研究下 Yii2 的 CSRF 防范机制

什么是 CSRF 攻击?

简单说, 攻击者盗用了你的身份,以你的名义发送恶意请求。

 

最有效地一个方法原理是这样的:

Cookie Hashing, 让服务器发送给客户端的所有表单中都标示一个随机值_csrf,并同时在客户端的COOKIE中保存一个相关联的token;

验证的时候,服务端每次对接收到的请求_POST()过来的一个input hidden _csrf跟客户端的COOKIE中的token进行对照验证

攻击者攻击的原理是利用了客户端的COOKIE,但是攻击者是得不到COOKIE具体的内容的,他只是利用(这里抛开XSS攻击的可能性,由于用户的Cookie很容易由于网站的XSS漏洞而被盗取,这就另外的1%。一般的攻击者看到有需要算Hash值,基本都会放弃了);所以攻击者没法在攻击URL中加入token,这样就无法通过验证。

这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了:>

来看看: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

禁用enableCookieValidation让分析CSRF的过程变得简单

在 config文件中禁用:

'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开始寻找csrf

3.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

终于找到了CSRF

public 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>

正好也是在 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都是由 Yii::$app->request处理的

head中

$request->getCsrfToken()

form中

$request->csrfParam
$request->getCsrfToken()

看来 整个验证的流程都是由getCsrfToken()触发的。

3.3 研究源码

来个流程图(手绘版):

   
3189 次浏览       25
 
相关文章

iOS应用安全开发,你不知道的那些事术
Web安全之SQL注入攻击
移动APP安全在渗透测试中的应用
从Google备份互联网看“数据安全”
 
相关文档

web安全设计与防护
互联网海量内容安全处理技术
黑客攻击与防范技术
WEB黑盒安全检测
 
相关课程

WEB网站与应用安全原理与实践
web应用安全架构设计
创建安全的J2EE Web应用代码
信息安全问题与防范
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

iOS应用安全开发
Web安全之SQL注入攻击
APP安全在渗透测试中的应用
初探PHP的SQL注入攻击的技术
从Google备份看“数据安全”
更多...   

WEB网站与应用安全原理与实践
web应用安全架构设计
创建安全的J2EE Web应用代码
注册信息安全专业人员(CISP)
信息安全管理
信息安全问题与防范

中国银行 信息安全技术及深度防御
Web应用安全架构、入侵检测与防护
某财税领域知名IT服务商 Web安全测试
普瑞克斯 web安全设计、测试与优化
北京和利时 性能和安全性测试
SUN中国工程研究院 JSF框架、安全
更多...