jquery ajax call forbidden by codeigniter 3 csrf



Windows 10, Codeigniter 3, jQuery 3

我正在测试 ajax 函数,我正在使用 $.post 函数将数据加载到div 中,并发送到读取文件并发回内容的控制器方法(我知道还有其他方法可以做到这一点,但这是一个测试(。ajax 调用如下所示

var btn = 'a[href="click-help"]'
$(btn).click(function(){
$.post(
base_url+'site/cal_help', 
function(data){
$('.cal-help').html(data);
});
}
return false;
});

您可以看到单击按钮不是表单,而是链接。当我将 csrf 设置为 false 时,这工作正常,但如果启用了 csrf,控制台会将调用显示为禁止。在网上研究后,我尝试按如下方式传递数据:

{
'<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
}, 

但这无济于事。如何在不将 csrf 设置为 false 的情况下修复它,如果我想将其用于站点中的其他元素,我宁愿不这样做?

我仍在努力解决这个问题,我发现了一些更有趣的事情:

尽管您可以像这样使用 Codeigniter Security 类:

<?php echo $this->security->get_csrf_token_name(); ?>
<?php echo $this->security->get_csrf_hash(); ?>

在视图中并且这些功能有效,您还应该能够在脚本文件中使用它们,例如

var hash = '<?php echo $this->security->get_csrf_hash();?>';
console.log(hash);

这似乎在视图中的脚本标记中工作,但如果在单独的脚本中.js控制台仅显示打印的代码。为什么会这样呢?

但是,我深入研究了js字符串方法,发现以下内容可以检索哈希:

//get all cookies
var x = document.cookie;
//search for the csrf cookie name
var posname = x.search('csrf_cookie_name');
//slice out hash itself which is always 32 characters long and these numbers work
var hash = x.slice(posname+17,posname+49);
console.log(hash);

建立等于哈希的变量后,可以将以下数据添加到 ajax 调用中:

{
'csrf_test_name' : hash
},

我将所有这些放在"点击"功能中,以便它找到最新版本的cookie。所以我最终得到了这样的东西:

var btn = '.btn-cal-help a';
$(btn).click(function(){
var x = document.cookie;
var posname = x.search('csrf_cookie_name');
var hash = x.slice(posname+17,posname+49);
//console.log(hash);    
$.post(
base_url + 'site/cal_help', 
{
'csrf_test_name' : hash
}, 
function(data){
$('.cal-help').html(data);
});
}
return false;
});

现在这对我有用(在我的本地服务器上 - wamp(,即使我也将"csrf_regenerate"设置为 TRUE。

我确实面临着在所有 ajax 请求中启用 CSRF 保护的项目的类似问题。然后我发现发生这种情况是因为 csrf 令牌在每个请求上重新生成,这将导致禁止错误,因为令牌不匹配。因此,解决方案是在每个请求上关闭CSRF令牌生成。您可以通过在 config.php 文件中设置此选项来执行此操作。

$config['csrf_regenerate'] = FALSE;

请注意,当我检查 laravel 的 CSRF 令牌时,它不会在所有请求中更改。因此,将 csrf 再生选项更改为 false 不会导致任何重大安全问题。如果上述方法不适合您,请在下面发表评论。

簡單地這樣。获取每个新请求的令牌和哈希,并将其附加到您的帖子数据

在您的模型/控制器中放置类似的东西

$reponse = array(
'csrfName' => $this->security->get_csrf_token_name(),
'csrfHash' => $this->security->get_csrf_hash()
);
// Your logic
return $this->output
->set_content_type('application/json')
->set_status_header(200)
->set_output(json_encode(array("regen" => $reponse, "response" => array("status" => $status, "message" => $message))));

在 JavaScript 部分

var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
$.ajax({
url: __URL__,
type: "POST",
data: $form.serialize() + "&" + csrfName + "=" + csrfHash,
mimeType: "multipart/form-data",
contentType: false,
dataType: 'json',
cache: false,
processData: false,
success: function (data) {
csrfName = data.regen.csrfName;
csrfHash = data.regen.csrfHash;
if (data.response.status) // if STATUS = TRUE
{
if (data.response.message === "__WHATEVER__") {
// and message === "__WHATEVER__"
}
}
}
});

$config['csrf_protection'] = TRUE;设置为FALSE并不是解决这个问题的好方法。在 AJAX请求期间发生的情况是,当请求发送到控制器时,它将在提交期间验证有效的令牌。因此,您需要传递令牌名称和哈希令牌,以便将其读取为有效。

在这里。。。

$.ajax({
url: url,
type: "post",
data: {'<?php echo $this->security->get_csrf_token_name(); ?>':'<?php echo $this->security->get_csrf_hash(); ?>'},
success:function() {
//do stuff here...
}
});

最新更新