在 Yii2 中,启用 CSRF 防护是非常重要的,以防止跨站请求伪造(Cross-Site Request Forgery, CSRF)攻击。CSRF 攻击是指攻击者通过伪装用户的请求,向服务器发送恶意指令。启用 CSRF 防护可以确保只有经过认证的用户才能提交表单,从而提高应用的安全性。
使用场景
- 登录表单:确保只有经过认证的用户才能提交登录请求。
- 注册表单:确保只有经过认证的用户才能提交注册请求。
- 编辑资料表单:确保只有经过认证的用户才能提交编辑个人资料的请求。
- 支付表单:确保只有经过认证的用户才能提交支付请求。
底层原理
CSRF 防护的基本原理是在每个表单中嵌入一个唯一的 CSRF 令牌,并在服务器端验证这个令牌。具体步骤如下:
- 生成 CSRF 令牌:在用户会话中生成一个唯一的 CSRF 令牌。
- 嵌入 CSRF 令牌:将 CSRF 令牌嵌入到每个表单中。
- 验证 CSRF 令牌:在表单提交时,服务器端验证提交的 CSRF 令牌是否与会话中的令牌匹配。
如何在 Yii2 中启用 CSRF 防护
1. 配置应用
Yii2 默认启用了 CSRF 防护,但你需要确保配置文件中正确设置了相关选项。
在 config/web.php
中,确保 request
组件的 enableCsrfValidation
属性设置为 true
:
return [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'components' => [
'request' => [
'cookieValidationKey' => 'your_secret_key',
'enableCsrfValidation' => true,
],
// 其他组件配置
],
// 其他配置
];
2. 在视图中使用 CSRF 令牌
在每个表单中嵌入 CSRF 令牌。Yii2 提供了 Html::csrfMetaTags()
方法来生成 CSRF 令牌的元标签,以及 Html::beginForm()
方法来生成包含 CSRF 令牌的表单。
示例:登录表单
<!-- views/site/login.php -->
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(); ?>
<?= Html::csrfMetaTags() ?>
<?= $form->field($model, 'username')->textInput() ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<button type="submit">Login</button>
<?php ActiveForm::end(); ?>
手动生成表单
如果你不想使用 ActiveForm
,也可以手动嵌入 CSRF 令牌:
<!-- views/site/login.php -->
<form method="post">
<?= Html::csrfMetaTags() ?>
<input type="text" name="username">
<input type="password" name="password">
<button type="submit">Login</button>
</form>
3. 处理 AJAX 请求
对于 AJAX 请求,你需要手动传递 CSRF 令牌。可以在 AJAX 请求中添加一个 X-CSRF-Token
头,或者在请求参数中包含 CSRF 令牌。
示例:使用 jQuery 发送 AJAX 请求
$.ajax({
url: '/site/login',
type: 'POST',
data: {
username: 'user',
password: 'pass',
_csrf: $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
console.log(response);
}
});
4. 自定义错误处理
如果 CSRF 验证失败,默认情况下 Yii2 会抛出一个 yii\web\ForbiddenHttpException
异常。你可以自定义错误处理逻辑,例如返回一个友好的错误页面。
示例:自定义错误处理
在 config/web.php
中添加错误处理器:
return [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'components' => [
'request' => [
'cookieValidationKey' => 'your_secret_key',
'enableCsrfValidation' => true,
],
'errorHandler' => [
'errorAction' => 'site/error',
],
],
'params' => $params,
];
在 SiteController
中添加错误处理动作:
namespace app\controllers;
use Yii;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionError()
{
$exception = Yii::$app->errorHandler->exception;
if ($exception instanceof \yii\web\ForbiddenHttpException) {
return $this->render('csrf-error', ['exception' => $exception]);
}
return $this->render('error', ['exception' => $exception]);
}
}
总结
通过上述步骤,你可以在 Yii2 中启用 CSRF 防护,确保所有表单提交都受到保护,防止跨站请求伪造攻击。这些措施不仅提高了应用的安全性,还增强了代码的健壮性和可靠性。