如何在CodeIgniter3中csrf_regeneration为true时使Ajax工作?

时间:2022-10-06 16:42:34

I'm currently working my project on CI3 and I have some problem on CSRF_Regeneration.

我目前正在研究CI3上的项目,我在CSRF_Regeneration上遇到了一些问题。

My purpose:

I'm going to use CSRF to protect my form data when user login and registration by check email existing or not when user input a email.

当用户输入电子邮件时,当用户登录和通过支票电子邮件注册时,我将使用CSRF来保护我的表单数据。

It is Work if CSRF_generation is False

如果CSRF_generation是假的,那就是工作

It is work when I confige CSRF_Regeneration to False And csrf_expire will expire at 7200.

当我将CSRF_Regeneration设置为False并且csrf_expire将在7200到期时,这是有效的。

Problem The problem will happen as below when I enable CSRF_generation to TRUE

问题当我将CSRF_generation设置为TRUE时,问题将发生如下

POST http://localhost/com/account/register 403 (Forbidden)

Here is Ajax to check email is existing or not

这是检查电子邮件是否存在的Ajax

<script type="text/javascript">
    $(document).ready(function () {

        $("#email-error").css({'display': 'none', 'color': 'red'});
        $("#email").keyup(function () {
            var emailValue = $("#email"); // This is a bit naughty BUT you should always define the DOM element as a var so it only looks it up once
            var tokenValue = $("input[name='csrf_token_name']");
//            console.log('The Email length is ' + emailValue.val().length);
            if (emailValue.val().length >= 0 || emailValue.val() !== '') {
//                console.log('Token is ' + tokenValue.val()); // Now why is this not getting the coorect value?? It should
                $.ajax({
                    type: "post",
                    url: "<?php echo base_url('account/check_user_existing'); ?>",
                    data: {
                        '<?php echo $this->security->get_csrf_token_name(); ?>': tokenValue.val(),
                        email: $("#email").val()
                    },
                    dataType: "json",
                    cache: false,
                    success: function (data) {
//                        console.log('The returned DATA is ' + JSON.stringify(data));
//                        console.log('The returned token is ' + data.token);
                        tokenValue.val(data.token);
                        if (data.response == false) {
                            $("#email-error").css({'display': 'none'});
                            $(".form-error").css({'border': '', 'background-color': '', 'color': ''});
                            document.getElementById("csubmit").disabled = false;
                        } else {
                            $("#email-error").css({'display': 'inline', 'font-size': '12px'});
                            $(".form-error").css({'border': '1px solid red', 'background-color': 'rgba(255, 0, 0, 0.17)', 'color': 'black'});
                            document.getElementById("csubmit").disabled = true;
                        }
                    }
                });
            }
        });
    });
</script>

And here my form

在这里我的形式

<?PHP echo form_open('account', array('method' => 'POST', 'id' =>'createform')); ?>
 <div class="control-group">
   <label class="control-label"  for="lname">Last Name</label>
   <div class="control">
    <?PHP echo form_input('lastname', set_value('lastname', ''), 'id="lastname" class="form-control ln-error" ') ?>
    </div>
   </div>
 <div class="control-group">
   <label class="control-label"  for="fname">First Name</label>
     <div class="control">
    <?PHP echo form_input('firstname', set_value('firstname', ''), 'id="firstname" class="form-control ln-error" ') ?>
     </div>
   </div>
  <div class="control-group">
  <label class="control-label"  for="email"> Email <span id="email-error">Email is existed</span></label>
   <div class="control">
     <?PHP echo form_input('email', set_value('email', ''), 'id="email" class="form-control ln-error" placeholder="Example@website.com" ') ?>
      </div>
     </div>
  <div class="control-group">
      <label class="control-label" >Password</label>
       <div class="control">
       <?PHP echo form_password('pass', set_value('pass', ''), 'id="pass" class="form-control ln-error" ') ?>
      </div>
     </div>
  <div class="control-group">
     <div class="controls">
       <?PHP echo form_submit('csubmit', "Create Account", 'id="csubmit" class="btn btn-success btn-lg" ') ?>
       </div>
      </div>
<?PHP echo form_close(); ?>

And here is method of controller to check user

这里是控制器检查用户的方法

public function check_user_existing() {

        $data = $this->input->post('email'); // This should be passed in as a parameter as depending upon Form Names isn't that good.
        $new_token = $this->security->get_csrf_hash();
        $response = FALSE; // Set the default so we know what it is in case the IF fails or we could use an else at the end but this is nicer.
        $check_email = $this->user->check_user_exist_email($data);
        if ($check_email == TRUE) {
            $response = TRUE; // Change it to TRUE if it's true but our $response Always has a KNOWN Value :)
        }
        echo json_encode(array('response' => $response, 'token' => $new_token));
        exit(); // This is here for safety... Terminate and leave!
    }

Thanks for your advice

谢谢你的建议

2 个解决方案

#1


3  

I had this issue and I didn't want to set csrf_regeneration to FALSE as it is less secure.

我有这个问题,我不想将csrf_regeneration设置为FALSE,因为它不太安全。

So what I did was the following:

所以我做的是以下内容:

csrf_token_name = '<?php echo $this->security->get_csrf_token_name(); ?>';
csrf_cookie_name = '<?php echo $this->config->item('csrf_cookie_name'); ?>';
$(function ($) {
    // this bit needs to be loaded on every page where an ajax POST 
    var object = {};
    object[csrf_token_name] = $.cookie(csrf_cookie_name);
    $.ajaxSetup({
        data: object
    });
    $(document).ajaxComplete(function () {
        object[csrf_token_name] = $.cookie(csrf_cookie_name);
        $.ajaxSetup({
            data: object
        });
    });
});

And if you are using blueimp/jQuery-File-Upload you can do the following:

如果您使用的是blueimp / jQuery-File-Upload,您可以执行以下操作:

$('#fileupload').bind('fileuploadsubmit', function (e, data) {
    data.formData = [
        {name: csrf_token_name, value: $.cookie(csrf_cookie_name)}
    ]
});

References:

  1. https://www.codeigniter.com/user_guide/libraries/security.html
  2. http://jerel.co/blog/2012/03/a-simple-solution-to-codeigniter-csrf-protection-and-ajax
  3. http://api.jquery.com/ajaxcomplete/
  4. https://api.jquery.com/jquery.ajaxsetup/
  5. https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-submit-additional-form-data#setting-formdata-on-upload-start

#2


1  

what you can do is first create a function which will return the CSRF token generated by codeigniter like this

你可以做的是首先创建一个函数,它将返回由codeigniter生成的CSRF令牌

public function get_csrf()
{

    $error['csrf_token'] = $this->security->get_csrf_hash();
    echo json_encode($error);
    die();
}

Then in the ajax call first get this token and then send this token along with your ajax call like this. //first ajax call to get csrf token

然后在ajax调用中首先获取此令牌,然后将此令牌与您的ajax调用一起发送。 //首先调用ajax来获取csrf令牌

$.ajax({
'async': true,
'type': "GET",
'dataType': 'json',
//first ajax url to get csrf token
'url': "<?php echo base_url('main/get_csrf'); ?>",
'success': function (data) {
    tmp = data;
    csrf_token = data.csrf_token;

    //your second ajax call will contain one parameter i.e your csrf token name for eg 'csrf_test_name'
    $.ajax({
        'async': true,
        'type': "POST",
        'dataType': 'json',
        'data': {'email': email, 'social_media_name': 'google', 'csrf_test_name': csrf_token},
        //the url to your controller function
        'url': "<?php echo base_url('social/google_login'); ?>",
        'success': function (data) {
        }
    });
}

});

This works in my case. Tested.

这适用于我的情况。测试。

#1


3  

I had this issue and I didn't want to set csrf_regeneration to FALSE as it is less secure.

我有这个问题,我不想将csrf_regeneration设置为FALSE,因为它不太安全。

So what I did was the following:

所以我做的是以下内容:

csrf_token_name = '<?php echo $this->security->get_csrf_token_name(); ?>';
csrf_cookie_name = '<?php echo $this->config->item('csrf_cookie_name'); ?>';
$(function ($) {
    // this bit needs to be loaded on every page where an ajax POST 
    var object = {};
    object[csrf_token_name] = $.cookie(csrf_cookie_name);
    $.ajaxSetup({
        data: object
    });
    $(document).ajaxComplete(function () {
        object[csrf_token_name] = $.cookie(csrf_cookie_name);
        $.ajaxSetup({
            data: object
        });
    });
});

And if you are using blueimp/jQuery-File-Upload you can do the following:

如果您使用的是blueimp / jQuery-File-Upload,您可以执行以下操作:

$('#fileupload').bind('fileuploadsubmit', function (e, data) {
    data.formData = [
        {name: csrf_token_name, value: $.cookie(csrf_cookie_name)}
    ]
});

References:

  1. https://www.codeigniter.com/user_guide/libraries/security.html
  2. http://jerel.co/blog/2012/03/a-simple-solution-to-codeigniter-csrf-protection-and-ajax
  3. http://api.jquery.com/ajaxcomplete/
  4. https://api.jquery.com/jquery.ajaxsetup/
  5. https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-submit-additional-form-data#setting-formdata-on-upload-start

#2


1  

what you can do is first create a function which will return the CSRF token generated by codeigniter like this

你可以做的是首先创建一个函数,它将返回由codeigniter生成的CSRF令牌

public function get_csrf()
{

    $error['csrf_token'] = $this->security->get_csrf_hash();
    echo json_encode($error);
    die();
}

Then in the ajax call first get this token and then send this token along with your ajax call like this. //first ajax call to get csrf token

然后在ajax调用中首先获取此令牌,然后将此令牌与您的ajax调用一起发送。 //首先调用ajax来获取csrf令牌

$.ajax({
'async': true,
'type': "GET",
'dataType': 'json',
//first ajax url to get csrf token
'url': "<?php echo base_url('main/get_csrf'); ?>",
'success': function (data) {
    tmp = data;
    csrf_token = data.csrf_token;

    //your second ajax call will contain one parameter i.e your csrf token name for eg 'csrf_test_name'
    $.ajax({
        'async': true,
        'type': "POST",
        'dataType': 'json',
        'data': {'email': email, 'social_media_name': 'google', 'csrf_test_name': csrf_token},
        //the url to your controller function
        'url': "<?php echo base_url('social/google_login'); ?>",
        'success': function (data) {
        }
    });
}

});

This works in my case. Tested.

这适用于我的情况。测试。