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...
}
});