通过 Yii2 中的链接使用 AJAX 提交时的 CSRF 问题

Posted

技术标签:

【中文标题】通过 Yii2 中的链接使用 AJAX 提交时的 CSRF 问题【英文标题】:CSRF issue when using AJAX submit via link in Yii2 【发布时间】:2015-11-15 19:05:12 【问题描述】:

我正在使用Yii2,并且一直在使用通过 AJAX 进行 POST 的链接来检索一些数据,并且它一直运行良好;但是我注意到,如果我从页面中删除一个表单,它就不再起作用,并且由于某种原因不会在标题中发送 CSRF 令牌。

我在页面上还有几个隐藏表单,它们在两种情况下都存在。

以下是两种情况的总结:

工作情况:

页面上的所有 CSRF 都是 same - 名为 csrf-tokenmeta 标签,页面上的主表单以及所有隐藏表单,它们都使用相同的 CSRF 令牌这与请求标头中发送的令牌相同。

...现在我更改场景,以便生成非工作版本。

不工作情况:

在这种情况下,页面上没有主窗体。名为csrf-tokenmeta 标记与上一个请求具有不同的CSRF 令牌,但由于某种原因,所有隐藏 表单都具有与上一个 请求相同的CSRF 令牌/页面加载。

当我点击 POST 通过 AJAX no CSRF 令牌在标头中发送的链接时。

如果重要的话:

main 表单加载了ActiveForm::begin(...),而隐藏 表单加载了html::beginForm(...)

知道这里发生了什么吗?为什么它不起作用?为什么隐藏表单有来自先前请求的 CSRF 令牌?

【问题讨论】:

【参考方案1】:

工作:好的,所以我对这个问题的理解是,当你使用 ActiveFrom 时,它会创建一个新的 CSRF 令牌并存储在一个 cookie 中,比如 xxxxxx,所以主表单和相应的 HTML 表单在该页面从此 cookie 中读取 csrf 值。

不工作: 现在,您进入了一个新页面,因此 Yii 引擎在服务器端创建了一个 csrf(这就是为什么您会看到带有新 csrf 令牌的元标记),除非您调用ActiveForm,没有办法在客户端更新cookie。因此,所有其他 HTML 表单都尝试从 cookie 值中读取以获取 csrf 值,该值最终是旧的。

因此,除非您可能调用动态创建令牌的函数,否则我看不到值发生变化。所以值保持不变。

我的想法是尝试一下

'_csrf="<?php echo Yii::$app->request->csrfToken ?>" '

在 HTML 页面中,您没有 Main 表单来从请求中返回值。

我没试过,但应该可以。

或者对于 Ajax

<head>
   .......
   <?= Html::csrfMetaTags() ?>
</head>

var csrfToken = $('meta[name="csrf-token"]').attr("content");
$.ajax(
         url: 'request',
         type: 'post',
         dataType: 'json',
         data: param1: param1, _csrf : csrfToken,
);

【讨论】:

我已经在我的元标记中使用了Html::csrfMetaTags(),所以总是在那里,一旦我开始使用像这样通过 JS 传递令牌的解决方案,问题就停止了。我没有回答这个问题,因为我认为这只解决了 AJAX 问题,但似乎隐藏的表单现在也总是得到一个新的令牌。顺便说一句,Html::beginForm() 也会生成一个令牌,因此您不需要调用 ActiveForm 来获取新令牌。

以上是关于通过 Yii2 中的链接使用 AJAX 提交时的 CSRF 问题的主要内容,如果未能解决你的问题,请参考以下文章

Yii2 modal中 ajax提交表单

yii2 表单提交一直报错 或者页面脚本写ajax,用firbug调试总是找不到地址页面404

使用 Yii 2 提交两次 Ajax 表单

yii2 ajax post设置csrf

批量处理使用ajax提交时的操作

通过 Ajax 发布到 MVC 控制器