Yii2 CSRF
2019-08-12 本文已影响0人
胡乱唱歌ing
概述:Yii2 默认全局开启csrf验证的
1.配置csrf隐藏表单的input name
'components' => [
'request' => [
'csrfParam' => '_csrf-frontend',
],
]
2.表单嵌入csrf
<input type="hidden" name="<?php echo Yii::$app->request->csrfParam;?>" value="<?php echo Yii::$app->request->getCsrfToken();?>" />
3.yii2 csrf验证机制
yii\web\Controller
/**
* {@inheritdoc}
*/
public function beforeAction($action)
{
if (parent::beforeAction($action)) {
//调用csrf_token 验证方法
if ($this->enableCsrfValidation && Yii::$app->getErrorHandler()->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) {
throw new BadRequestHttpException(Yii::t('yii', 'Unable to verify your data submission.'));
}
return true;
}
return false;
}
yii\web\Request
public function validateCsrfToken($clientSuppliedToken = null)
{
$method = $this->getMethod();
// only validate CSRF token on non-"safe" methods https://tools.ietf.org/html/rfc2616#section-9.1.1
if (!$this->enableCsrfValidation || in_array($method, ['GET', 'HEAD', 'OPTIONS'], true)) {
return true;
}
//获取服务器的csrftoken
$trueToken = $this->getCsrfToken();
if ($clientSuppliedToken !== null) {
return $this->validateCsrfTokenInternal($clientSuppliedToken, $trueToken);
}
//验证客户端传过来的csrf_token
return $this->validateCsrfTokenInternal($this->getBodyParam($this->csrfParam), $trueToken)
|| $this->validateCsrfTokenInternal($this->getCsrfTokenFromHeader(), $trueToken);
}
4.客户端如何传递csrf_token
form表单POST提交
<input type="hidden" name="<?php echo Yii::$app->request->csrfParam;?>" value="<?php echo Yii::$app->request->getCsrfToken();?>" />
AJAX提交 yii已做了自动处理
yii.js
function initCsrfHandler() {
// automatically send CSRF token for all AJAX requests
$.ajaxPrefilter(function (options, originalOptions, xhr) {
if (!options.crossDomain && pub.getCsrfParam()) {
xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken());
}
});
pub.refreshCsrfToken();
}
5.为什么每次刷新界面csrf_token都会刷新变化,而不影响验证呢?
csrf_token 是存在会话的cookie中的,而每次都变化是Yii2做了处理,尽管输出到界面的值不断变化,但存在cookie里面的真正值是不变的。
public function getCsrfToken($regenerate = false)
{
if ($this->_csrfToken === null || $regenerate) {
$token = $this->loadCsrfToken();
if ($regenerate || empty($token)) {
$token = $this->generateCsrfToken();
}
$this->_csrfToken = Yii::$app->security->maskToken($token); //这里经过处理csrf_token每次变化,但是$token始终唯一
}
return $this->_csrfToken;
}