Codeigniter CSRF 仅对一次 ajax 请求有效
Codeigniter CSRF valid for only one time ajax request
我想在 jQuery 发生更改事件时在服务器上上传图片,但是使用 codeigniter csrf 我只能上传一次图片。如何使用 ajax 为多个 requests.Please 上传图片 设置此
时请记住
config['csrf_protection'] = FALSE;
然后我可以发送多个请求 jQuery onchange 事件但是当 csrf_protection 将是 false 时我认为 csrf 没有优势。所以问题是如何在 csrf_protection 启用时使用 ajax 发送多个请求。我的 jquery 代码如下
$("#avatar").change(function(){
var link = $("#avatar").val();
$.ajax({
url : "<?php echo base_url('main/test'); ?>",
type: 'post',
data: {'<?php echo $this->security->get_csrf_token_name(); ?>':'<?php echo $this->security->get_csrf_hash(); ?>',"id":"hello","link":link},
success : function(data)
{
alert(data);
}
});
});
我的控制器:
public function test()
{
$config['upload_path'] = './uploads/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 500;
$config['max_width'] = 260;
$config['max_height'] = 260;
$this->load->library('upload', $config);
if (!$this->upload->do_upload('link')) {
echo "error";
} else {
$data = array('upload_data' => $this->upload->data());
$image_name = $data['upload_data']['file_name'];
echo $image_name;
}
}
在我看来,您应该尝试在每次请求时重新创建您的 csrf 令牌
试试这个代码示例...
对于js函数
var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
("#avatar").change(function(){
var link = $("#avatar").val();
var dataJson = { [csrfName]: csrfHash, id: "hello", link: link };
$.ajax({
url : "<?php echo base_url('main/test'); ?>",
type: 'post',
data: dataJson,
success : function(data)
{
csrfName = data.csrfName;
csrfHash = data.csrfHash;
alert(data.message);
}
});
});
和控制器
public function test() {
$config['upload_path'] = './uploads/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 500;
$config['max_width'] = 260;
$config['max_height'] = 260;
$reponse = array(
'csrfName' => $this->security->get_csrf_token_name(),
'csrfHash' => $this->security->get_csrf_hash()
)
$this->load->library('upload', $config);
if (!$this->upload->do_upload('link')) {
$reponse['message'] = "error";
}
else {
$data = array('upload_data' => $this->upload->data());
$image_name = $data['upload_data']['file_name'];
$reponse['message'] = $image_name;
}
echo json_encode($reponse);
}
告诉我,祝你好运
注意:当有人要求您post为问题提供更多数据时,请不要post将其作为评论或答案,这是最好编辑问题本身并添加内容
您可以在 config.php
中设置
$config['csrf_regenerate'] = FALSE;
因此 csrf 保护在整个会话期间都有效,它将解决您的问题。
如果你设置
$config['csrf_regenerate'] = true;
然后 CI 每次请求都会生成新的 csrf 令牌,因此您的旧 csrf 令牌与新生成的 csrf 令牌不匹配
您需要做的就是在您的 AJAX 响应中重新加载 CSRF 令牌。就是这么简单!
编辑配置:
$config['csrf_exclude_uris'] = ['controller/method'];
数组可以包括所有列入白名单的controllers/methods 您希望为其禁用 csrf 保护。
数组还可以处理正则表达式,例如:
$config['csrf_exclude_uris'] = array(
'api/record/[0-9]+',
'api/title/[a-z]+'
);
有关详细信息,请访问 Codeigniter Documentation - Security Class
在每个页面加载的 js 文件中添加这个(我把它放在 jquery.js 的末尾)
$.ajaxSetup({
beforeSend:function(jqXHR, Obj){
var value = "; " + document.cookie;
var parts = value.split("; csrf_cookie_name=");
if(parts.length == 2)
Obj.data += '&csrf_token='+parts.pop().split(";").shift();
}
});
(请注意,在每个 ajax 请求中,您不能发送空数据)
"csrf_cookie_name" 在顶部定义在 config.php
$config['csrf_cookie_name'] = 'csrf_cookie_name';
请像我的代码一样尝试。它正在运行我的应用程序
您的视图文件
$token_name = $this->security->get_csrf_token_name();
$token_hash = $this->security->get_csrf_hash();
<input type="text" id="search-text" name="parent_name" placeholder="Search" value="" >
<input type="hidden" id="csrf" name="<?php echo $token_name; ?>" value="<?php echo $token_hash; ?>" />
设置 jquery post 方法后如下所示
// Get Keyup
jQuery( "#search-text").keyup(function() {
// Get Data
var val = jQuery("#search-text").val();
var hashValue = jQuery('#csrf').val();
// Get jquery post for ajax task
jQuery.post(
'<?php echo $base_controler; ?>',
{val:val,'<?php echo $this->security->get_csrf_token_name(); ?>':hashValue},
function(data)
{
// Get return data to decode
var obj = jQuery.parseJSON(data);
// Get csrf new hash value
var new_hash = obj.csrfHash;
// Set csrf new hash value update
jQuery('#csrf').val(new_hash);
}
);
});
请像下面这样设置你的控制器
$reponse = array(
'csrfName' => $this->security->get_csrf_token_name(),
'csrfHash' => $this->security->get_csrf_hash()
);
echo json_encode($reponse);
以上所有代码在每次请求时重新创建您的 csrf 令牌。
$config['csrf_regenerate'] = TRUE;
保持自动生成为真这样会更安全。
在类似的情况下,当 csrf 在第一个请求中过期时。我实现了什么
$(document).ajaxComplete(function (event, xhr, settings) {
let response = xhr.responseText,
let obj = JSON.parse(response),
let csrfData = obj.csrf;
document.querySelector('input[name="' + csrfData.name + '"]').value = csrfData.hash;
}); //Also here you can update any other non input element
在每个 ajax 响应中,我们传递 csrf 数据,其中最新的 csrf 数据将替换为当前数据
来自请求的示例响应
{
csrf : {
name : 'csrf_name',
hash : 'qw76sd7s6f78sdfs8dfs9df8cx9'
}
}
I update csrf token in every ajax request. Also don't choose this method if you are working with multi tab environment
每次您发出请求时,csrf_token
都会由 CI 更新。这就是 CSRF 只工作一次的原因。所以每次我们发出请求时,我们也需要更新 csrf_token。我通过这样做解决了这个问题。
Conroller:使用此代码获取更新的 csrf。
public function update_csrf()
{
$data['csrf_hash'] = $this->security->get_csrf_hash();
echo json_encode($data);
}
AJAX: 替换你的旧值 csrf name="csrf_token_name"
var jqXHR = $.ajax({
url: $(this).attr('action'),
type: 'POST',
data: $(this).serialize(),
dataType: 'json',
})
jqXHR.done(function(response) {
$('input[name=csrf_token_name]').val(response.csrf_hash); //update the csrf to the form
})
jqXHR.fail(function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
});
Important!: use dataType: 'json'
所以现在每次你有一个成功的请求,csrf_token
也会更新,你现在没有 403(禁止)错误.
也许你可以尝试使用 jquery cookie
首先你需要添加这个
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
然后将您的代码更改为此
$("#avatar").change(function(){
var link = $("#avatar").val();
$.ajax({
url : "<?php echo base_url('main/test'); ?>",
type: 'post',
data: {csrf_test_name: $.cookie('csrf_cookie_name'),"id":"hello","link":link},
dataType : "JSON",
success : function(data)
{
alert(data);
}
});
最后您可以尝试将 csrf_protection 设置为 true
[csrf_protection] = TRUE;
我想在 jQuery 发生更改事件时在服务器上上传图片,但是使用 codeigniter csrf 我只能上传一次图片。如何使用 ajax 为多个 requests.Please 上传图片 设置此
时请记住config['csrf_protection'] = FALSE;
然后我可以发送多个请求 jQuery onchange 事件但是当 csrf_protection 将是 false 时我认为 csrf 没有优势。所以问题是如何在 csrf_protection 启用时使用 ajax 发送多个请求。我的 jquery 代码如下
$("#avatar").change(function(){
var link = $("#avatar").val();
$.ajax({
url : "<?php echo base_url('main/test'); ?>",
type: 'post',
data: {'<?php echo $this->security->get_csrf_token_name(); ?>':'<?php echo $this->security->get_csrf_hash(); ?>',"id":"hello","link":link},
success : function(data)
{
alert(data);
}
});
});
我的控制器:
public function test()
{
$config['upload_path'] = './uploads/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 500;
$config['max_width'] = 260;
$config['max_height'] = 260;
$this->load->library('upload', $config);
if (!$this->upload->do_upload('link')) {
echo "error";
} else {
$data = array('upload_data' => $this->upload->data());
$image_name = $data['upload_data']['file_name'];
echo $image_name;
}
}
在我看来,您应该尝试在每次请求时重新创建您的 csrf 令牌
试试这个代码示例...
对于js函数
var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
("#avatar").change(function(){
var link = $("#avatar").val();
var dataJson = { [csrfName]: csrfHash, id: "hello", link: link };
$.ajax({
url : "<?php echo base_url('main/test'); ?>",
type: 'post',
data: dataJson,
success : function(data)
{
csrfName = data.csrfName;
csrfHash = data.csrfHash;
alert(data.message);
}
});
});
和控制器
public function test() {
$config['upload_path'] = './uploads/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 500;
$config['max_width'] = 260;
$config['max_height'] = 260;
$reponse = array(
'csrfName' => $this->security->get_csrf_token_name(),
'csrfHash' => $this->security->get_csrf_hash()
)
$this->load->library('upload', $config);
if (!$this->upload->do_upload('link')) {
$reponse['message'] = "error";
}
else {
$data = array('upload_data' => $this->upload->data());
$image_name = $data['upload_data']['file_name'];
$reponse['message'] = $image_name;
}
echo json_encode($reponse);
}
告诉我,祝你好运
注意:当有人要求您post为问题提供更多数据时,请不要post将其作为评论或答案,这是最好编辑问题本身并添加内容
您可以在 config.php
中设置$config['csrf_regenerate'] = FALSE;
因此 csrf 保护在整个会话期间都有效,它将解决您的问题。
如果你设置
$config['csrf_regenerate'] = true;
然后 CI 每次请求都会生成新的 csrf 令牌,因此您的旧 csrf 令牌与新生成的 csrf 令牌不匹配
您需要做的就是在您的 AJAX 响应中重新加载 CSRF 令牌。就是这么简单!
编辑配置:
$config['csrf_exclude_uris'] = ['controller/method'];
数组可以包括所有列入白名单的controllers/methods 您希望为其禁用 csrf 保护。
数组还可以处理正则表达式,例如:
$config['csrf_exclude_uris'] = array(
'api/record/[0-9]+',
'api/title/[a-z]+'
);
有关详细信息,请访问 Codeigniter Documentation - Security Class
在每个页面加载的 js 文件中添加这个(我把它放在 jquery.js 的末尾)
$.ajaxSetup({
beforeSend:function(jqXHR, Obj){
var value = "; " + document.cookie;
var parts = value.split("; csrf_cookie_name=");
if(parts.length == 2)
Obj.data += '&csrf_token='+parts.pop().split(";").shift();
}
});
(请注意,在每个 ajax 请求中,您不能发送空数据)
"csrf_cookie_name" 在顶部定义在 config.php
$config['csrf_cookie_name'] = 'csrf_cookie_name';
请像我的代码一样尝试。它正在运行我的应用程序
您的视图文件
$token_name = $this->security->get_csrf_token_name();
$token_hash = $this->security->get_csrf_hash();
<input type="text" id="search-text" name="parent_name" placeholder="Search" value="" >
<input type="hidden" id="csrf" name="<?php echo $token_name; ?>" value="<?php echo $token_hash; ?>" />
设置 jquery post 方法后如下所示
// Get Keyup
jQuery( "#search-text").keyup(function() {
// Get Data
var val = jQuery("#search-text").val();
var hashValue = jQuery('#csrf').val();
// Get jquery post for ajax task
jQuery.post(
'<?php echo $base_controler; ?>',
{val:val,'<?php echo $this->security->get_csrf_token_name(); ?>':hashValue},
function(data)
{
// Get return data to decode
var obj = jQuery.parseJSON(data);
// Get csrf new hash value
var new_hash = obj.csrfHash;
// Set csrf new hash value update
jQuery('#csrf').val(new_hash);
}
);
});
请像下面这样设置你的控制器
$reponse = array(
'csrfName' => $this->security->get_csrf_token_name(),
'csrfHash' => $this->security->get_csrf_hash()
);
echo json_encode($reponse);
以上所有代码在每次请求时重新创建您的 csrf 令牌。
$config['csrf_regenerate'] = TRUE;
保持自动生成为真这样会更安全。 在类似的情况下,当 csrf 在第一个请求中过期时。我实现了什么
$(document).ajaxComplete(function (event, xhr, settings) {
let response = xhr.responseText,
let obj = JSON.parse(response),
let csrfData = obj.csrf;
document.querySelector('input[name="' + csrfData.name + '"]').value = csrfData.hash;
}); //Also here you can update any other non input element
在每个 ajax 响应中,我们传递 csrf 数据,其中最新的 csrf 数据将替换为当前数据
来自请求的示例响应
{
csrf : {
name : 'csrf_name',
hash : 'qw76sd7s6f78sdfs8dfs9df8cx9'
}
}
I update csrf token in every ajax request. Also don't choose this method if you are working with multi tab environment
每次您发出请求时,csrf_token
都会由 CI 更新。这就是 CSRF 只工作一次的原因。所以每次我们发出请求时,我们也需要更新 csrf_token。我通过这样做解决了这个问题。
Conroller:使用此代码获取更新的 csrf。
public function update_csrf()
{
$data['csrf_hash'] = $this->security->get_csrf_hash();
echo json_encode($data);
}
AJAX: 替换你的旧值 csrf name="csrf_token_name"
var jqXHR = $.ajax({
url: $(this).attr('action'),
type: 'POST',
data: $(this).serialize(),
dataType: 'json',
})
jqXHR.done(function(response) {
$('input[name=csrf_token_name]').val(response.csrf_hash); //update the csrf to the form
})
jqXHR.fail(function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
});
Important!: use
dataType: 'json'
所以现在每次你有一个成功的请求,csrf_token
也会更新,你现在没有 403(禁止)错误.
也许你可以尝试使用 jquery cookie
首先你需要添加这个
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>
然后将您的代码更改为此
$("#avatar").change(function(){
var link = $("#avatar").val();
$.ajax({
url : "<?php echo base_url('main/test'); ?>",
type: 'post',
data: {csrf_test_name: $.cookie('csrf_cookie_name'),"id":"hello","link":link},
dataType : "JSON",
success : function(data)
{
alert(data);
}
});
最后您可以尝试将 csrf_protection 设置为 true
[csrf_protection] = TRUE;