我制作了一个简单的自动加载功能,可以在网站上向下滚动时加载内容。但是,当我在Codeigniter中启用CSRF保护时似乎存在一些问题。
我没有使用表格,因此我不知道当你滚动时我正在做我的帖子请求时如何将令牌从A发送到B.
我的JavaScript
if (location.href == baseurl) {
$(window).scroll(function(){
if ($(window).scrollTop() > $('body').height() / 2) {
if(doScroll == 1) {
$.post(baseurl + 'ajax/images',{'id' : ID}, function(data) {
$("#wrapper_content").append(data);
if(data == 'Det finnes ikke flere bilder i databasen, WTF!? Send inn forslag ASAP!') {
doScroll = 0;
}
ID++;
});
}
}
});
}
由于Codeigniter期望在所有POST请求中都有TOKEN,因此当CSRF启用时,我无法使其工作。有什么建议吗?
CSRF启用时出错
无法加载资源:服务器响应状态为500(内部服务器错误)
如果我关闭CSRF,一切都很有效......
答案 0 :(得分:13)
您可能想尝试我使用过的代码。效果很好:
<script type="text/javascript">
$(function(){
$('.answerlist').each(function(e){
$(this).click(function(){
var valrad = $("input[@name=answer]:checked").val();
var post_data = {
'ansid': valrad,
'<?php echo $this->security->get_csrf_token_name(); ?>' : '<?php echo $this->security->get_csrf_hash(); ?>'
};
$.ajax({
type: "POST",
url: "<?php echo base_url(); ?>online/checkanswer",
data: post_data,
success: function(msg){
/// do something
}
});
});
});
});
</script>
答案 1 :(得分:13)
正如其他人所说 - 你必须使用AJAX请求参数发布CSFR令牌名称及其值。这是一个简单的解决方案,可以自动将其附加到每个AJAX请求。
以下是我在主视图中的内容,因此在加载其他javascript文件之前,此代码位于每个页面上:
<script>
var csfrData = {};
csfrData['<?php echo $this->security->get_csrf_token_name(); ?>']
= '<?php echo $this->security->get_csrf_hash(); ?>';
</script>
<!-- ... include other javascript files -->
</body>
</html>
这是我在每个页面上都包含的javascript文件的一部分:
$(function() {
// Attach csfr data token
$.ajaxSetup({
data: csfrData
});
});
答案 2 :(得分:10)
如果需要,您可以在适当的位置回显令牌名称和哈希值。这样的事情。
echo $this->security->get_csrf_token_name()
和
echo $this->security->get_csrf_hash()
或者,您可以像往常一样使用form_open()并使用从javascript为您生成的隐藏输入。禁用CSRF功能是错误的方法。
答案 3 :(得分:0)
基本上你需要做的是从cookie中获取预期的csrf值(默认名称为“ci_csrf_token”),然后将其与其他数据一起发布。
您需要修改此行:
$.post(baseurl + 'ajax/images',{'id' : ID}, function(data) {
为:
$.post(baseurl + 'ajax/images',{'id' : ID,'ci_csrf_token' : $.cookie('ci_csrf_token')}, function(data) {
可能需要安装cookie插件(我不太确定;我使用的是mootools)。以下是更多信息:http://aymsystems.com/ajax-csrf-protection-codeigniter-20。
答案 4 :(得分:0)
以前的建议很有效,但我发现使用ajax设置自动将此标记应用于每个帖子,而不是使用可以在每个数据帖子中应用的变量,
$(document).ajaxSend(function(elm, xhr, s){
if(s.data){
s.data += '&';
}
s.data += '<?php echo $this->security->get_csrf_token_name(); ?>=<?php echo $this->security->get_csrf_hash(); ?>';
});
(适用于jquery-1.9.1。我不确定其他jquery版本)
答案 5 :(得分:0)
上述一些答案的唯一问题是csrf令牌仅对一个请求有效,因此如果您通过ajax发布帖子请求并且不刷新页面,则您将没有当前的csrf令牌下一个ajax发布请求。这是我的解决方案:
在CodeIgniter控制器中:
$data = array('data'=> 'data to send back to browser');
$csrf = $this->security->get_csrf_hash();
$this->output
->set_content_type('application/json')
->set_output(json_encode(array('data' => $data, 'csrf' => $csrf)));
$ data =要返回浏览器的数据
$ csrf =浏览器用于下一个ajax发布请求的新csrf令牌
显然你可以用其他方式输出它,但JSON主要用于ajax调用。还要在每个帖子响应中包含此标记,以用于下一个帖子请求
然后在你的下一个ajax请求(javascript)中:
var token = data.csrf;
$.ajax({
url: '/next/ajax/request/url',
type: 'POST',
data: { new_data: 'new data to send via post', csrf_token:token },
cache: false,
success: function(data, textStatus, jqXHR) {
// Get new csrf token for next ajax post
var new_csrf_token = data.csrf
//Do something with data returned from post request
},
error: function(jqXHR, textStatus, errorThrown) {
// Handle errors here
console.log('ERRORS: ' + textStatus + ' - ' + errorThrown );
}
});
另请注意,我已经csrf_token:token
将crf_token
替换为您在app / config / config.php中找到的令牌名称$config['csrf_token_name'] = 'csrf_token';
1} p>
答案 6 :(得分:0)
在审核了我的情况之后,我认为最好的选择是使用CSRF,但在每次尝试时重置令牌。否则,之前表达的关于重新使用cookie令牌的想法将允许攻击者使用相同的令牌重新提交数据数百次,这会使得该点的对象失效。
因此我创建了以下功能:
public function resetCSRF(){
$this->security = null;
$_COOKIE[$this->config->item('csrf_cookie_name')] = null;
load_class('Security', 'core');
$this->security->csrf_set_cookie();
return $this->security->get_csrf_hash();
}
例如,如果基于ajax的登录表单失败 - 在PHP中调用此函数,然后在接收失败的javascript端(此解决方案使用Jquery和来自w3schools的getCookie函数)将调用:
$('input[name="csrf_test_name"]').val(getCookie('csrf_cookie_name'));