如何在Cakephp 3中的ajax调用中定义CSRF令牌?同时,如何关闭某些ajax请求的CSRF?

7
在启用Csrf组件的Cakephp3中,如何在ajax调用中使用它?在ajax的beforeSend参数中,csrf令牌被设置在头部。那么csrfToken的值是什么?由于它会报错:

csrfToken未定义

beforeSend: function(xhr){
    xhr.setRequestHeader('X-CSRF-Token', csrfToken);
},

同时,我该如何针对某些 Ajax 调用禁用 Csrf 组件。

3个回答

7

CSRF组件将当前令牌写入请求参数中,名称为_csrfToken,您可以通过请求对象的param()方法(或自CakePHP 3.4起之后的getParam()方法)获取它:

beforeSend: function(xhr){
    xhr.setRequestHeader(
        'X-CSRF-Token',
        <?= json_encode($this->request->param('_csrfToken')); ?>
    );
},

为了使令牌在所有脚本中可用,例如可以将其作为全局变量在您的布局模板中进行设置:

<script>
var csrfToken = <?= json_encode($this->request->param('_csrfToken')) ?>;
// ...
<script>

你可以轻松地在所有 AJAX 请求中使用它:
setRequestHeader('X-CSRF-Token', csrfToken);

如果需要禁用CSRF组件,则可以从控制器事件管理器中移除它。您需要确定何时需要这样做,例如针对特定操作,如下所示:

public function beforeFilter(\Cake\Event\Event $event)
{
    parent::beforeFilter($event);

    if ($this->request->param('action') === 'actionXyz') {
        $this->eventManager()->off($this->Csrf);
    }
}

如果您正在使用CSRF中间件,则令牌仍然可用作名为_csrfToken的请求参数。但是禁用中间件的方法不同,请参见例如Cakephp 3.5.6为控制器禁用CSRF中间件
另请参阅:
- Cookbook > Request & Response Objects > Request Parameters - Cookbook > Controllers > Components > CSRF > Using the CsrfComponent - Cookbook > Controllers > Components > CSRF > Disabling the CSRF Component for Specific Actions

谢谢回复。 :) - ParminderBrar
这可能是一个快速解决方案,但我认为我们不应该禁用 CSRF 安全组件。它的存在是有原因的。在我的情况下,在使用 ajax 之前序列化表单就可以解决问题了。 我认为,在这种情况下你也不需要使用 before-send。 - Invincible
@Invincible 我认为这有点过于笼统了,使用头文件是正确/明智的方法,有许多情况需要使用它们。例如,可能根本没有表单可序列化,或者表单可能不是通过表单助手创建的,因此其中不会有任何令牌。虽然建议使用CSRF保护,但有些情况下禁用它完全没问题,甚至有时是必需的,例如在API(或类似的端点)中,这些端点接受“外部”非表单请求,并使用身份验证机制(或根本没有机制)来防止CSRF攻击。 - ndm
@ndm 是的,完全同意。这取决于情况。 - Invincible

3

每个表单都有一个隐藏的_csrfToken字段,当您启用Csrf组件时,它会自动添加。现在您可以通过jquery轻松获取此字段的令牌,例如$('[name="_csrfToken"]').val()

一个ajax调用将如下所示:

$.ajax({
   url: 'someUrl',
   headers : {
      'X-CSRF-Token': $('[name="_csrfToken"]').val()
   },
   type: 'post',
   ...
});

0

CakePHP 3

请不要为任何特定操作解锁字段/禁用CSRF安全组件。这对于表单安全非常重要。

对于那些遇到"请求已被拦截""表单篡改错误""您未被授权访问该位置""POST数据中有意外字段"的人,这主要是由于CSRF组件按预期工作。

禁用或修改它并不是一个解决方案。相反,请遵循正确的方法。在上述情况下,请尝试序列化表单,这应该会产生魔力。

var el = $("#xyzForm");

var ajaxTPCalls = el.serializeArray();
  $.ajax({
                            type: el.attr('method'),
                            async: true,
                            url:  el.attr('action'),
                            data: ajaxTPCalls,
                            dataType: "json",
                            cache: false,
                            success: function (data) {

                                toastr.success(data.message, data.title);
                            },
                            error: function (jqXHR) {
                                if (jqXHR.status == 403) {
                                    $("body").html(jqXHR.responseText);
                                }
                            }
                        });

这样做可以禁用CSRF或解锁任何字段。


令人沮丧的是,即使我使用序列化方法,我仍然会遇到“请求数据中未找到_Token”的问题。该表单是使用FormHelper创建的,并且其中包含所有正确的字段... - almcnicoll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接