没有 cookie 的 Yii2 中的 CSRF 验证

CSRF validation in Yii2 without cookies

在我的 Yii2 应用程序中有一个用户提交的表单。该站点已启用 CSRF 验证,但如果用户禁用了 cookie,则会抛出错误。处理这种情况的最佳方法是什么?我真的不想禁用 CSRF 验证以确保表单仅从我的站点提交。不涉及登录过程。对用户来说只是一次性的使用情况。谢谢。

您可以通过将 yii\web\Request 组件的 enableCsrfCookie 属性 设置为 false 来强制您的应用程序将 CSRF 令牌而不是 cookie 存储在会话中。 您可以在 web.php 配置中执行此操作:

$config = [
    // ...
    'components' => [
        'request' => [
            'enableCsrfCookie' => false,
        ],
        // ...
    ],
    // ...
];

但这会导致应用程序为每个请求启动会话。此外,默认情况下会话使用 cookie 来存储会话 ID,因此如果您想避免使用任何 cookie,最终可能不会有太大改进。

您还可以扩展 yii\web\Request 并覆盖其方法 generateCsrfToken()loadCsrfToken() 以使用不同的令牌存储方式。但请记住,默认情况下无法识别哪些请求来自同一会话。您必须在客户端中保存某种 sessionId,然后将其发送回服务器,以便能够将提交表单的请求与 CSRF 令牌和生成 CSRF 令牌的请求配对。

另一种可能性是关闭标准的 CSRF 保护并实施您自己的表单保护。例如,您可以将一些密钥存储在应用程序配置中。 然后在生成表单时,您将使用 yii\base\Security::hashData() 方法将时间戳添加到您的表单中:

$timestamp = Yii::$app->security->hashData(time(), $yourSecurityKey);
Html::hiddenInput('my-csrf', $timestamp);

然后您可以在您的控制器操作中验证它:

$timestamp = Yii::$app->security->validateData(
   Yii::$app->request->post('my-csrf'),
   $yourSecurityKey
);

if ($timestamp === false || $timestamp < (time() - $timeLimitInSeconds)) {
     //Do something when CSRF validation is not valid (for example throw bad request exception)
}

// continue form processing

警告:示例中的保护不如标准 CSRF 保护安全,因为有人可以从您的应用程序请求表单以获取生成的令牌,而不是在从他们的站点提交的表单中使用令牌在有限的时间内.

您可以尝试的另一件事是检查用户是否启用了 cookie? 现在是您的偏好,您是想在您的网站开始时还是在用户填写表格时检查它。

正如我在许多网站上看到的那样,他们要求我们启用 cookie 以继续。 您可以检查以下 link 来检查 cookie 是启用还是禁用。 https://www.dummies.com/programming/php/check-whether-php-cookies-are-enabled/

如果你是比较JavaScript的人,还可以查看以下link.

Check if cookies are enabled

我建议您在打开表单页面时显示一个警告,提示未启用 cookie。

谢谢!!希望对你有帮助。