【问题标题】:Why Jquery Ajax get 403 (forbidden) errors with csrf_protection enable in Codeigniter3.0.0?为什么 Jquery Ajax 在 Codeigniter3.0.0 中启用 csrf_protection 时会出现 403(禁止)错误?
【发布时间】:2015-04-26 16:30:36
【问题描述】:

我正在使用 jquery 和 CodeIgniter3.0.0 开发注册 但是在我将 csrf_protection 启用为 true 后,我的 ajax 将停止工作。但是如果我将 csrf_protection 禁用为 False,我的 ajax 将完美运行。

这是我的表格

<?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(); ?>

完成表单后,我使用 Jquery 验证表单字段

<strip>
 $(document).already(function(){
       $("#email").keyup(function () {
            if ($("#email").val().length >= 0 || $("#email").val() !== '') {
                ajax_call();
            }
        });

 });

function ajax_call() {
        $.ajax({
            type: "post",
            url: "<?php echo base_url('account/check_user_existing'); ?>",
//            data: $("#createform").serialize(),
            data: {
                '<?php echo $this->security->get_csrf_token_name(); ?>': '<?php echo $this->security->get_csrf_hash(); ?>',
                 email:$("#email").val()
    },
            success: function () {
                alert("success");
            },
            dataType: "text",
            cache: false,
            success: function (respond) {
                if ($.trim(respond) === "true") {
                    $("#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;
                } else {
                    $("#email-error").css({'display': 'none'});
                    $(".form-error").css({'border': '', 'background-color': '', 'color': ''});
                    document.getElementById("csubmit").disabled = false;
                }
            }
        });
    }
</strip>

在我通过点击表单元素进行验证后,我会得到如下图所示的错误

【问题讨论】:

  • 不知道你是如何让这段代码工作的跨度>

标签: jquery ajax codeigniter


【解决方案1】:

在设置您的代码以进行操作后,我发现 CSRF 令牌在每次 AJAX 调用时都会重新生成(更改)。

所以第一次按键没问题 - 后续按键会导致帖子被拒绝,因为您的 CSRF 令牌不再有效。

Quick Nasty Fix:你可以做的一件事就是改变

//$config['csrf_regenerate'] = TRUE;
$config['csrf_regenerate'] = FALSE;

理想情况下,您可以将其设置为 TRUE,并在每次发布响应时发回新令牌。我正在努力。

CSRF Regenerate = true 修复:

处理您希望通过设置在每个帖子上重新生成 CSRF 令牌的情况

$config['csrf_regenerate'] = TRUE;

你可以这样做... 注意:我有一些 console.log 调试代码 - 你可以删除它。

<script>    
function ajax_call() {
            var tokenValue = $("input[name='csrf_test_name']");
            console.log('Token is ' + tokenValue.val());
            $.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': '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;
                    } else {
                        $("#email-error").css({'display': 'none'});
                        $(".form-error").css({'border': '', 'background-color': '', 'color': ''});
                        document.getElementById("csubmit").disabled = false;
                    }
                }
            });
        }
</script>

注意:dataType 由 text 改为 json。我还硬编码了不可取的令牌名称。这可以通过多种方式传递(适合您的练习)。

以及 account/check_user_existing

的测试代码
    public function check_user_existing(){
            $new_token = $this->security->get_csrf_hash();
            $response = FALSE;
            if($this->input->post('email') == 'testmy@email.address')
            {
                $response = TRUE;
            }
            echo json_encode(array('response'=>$response,'token'=>$new_token));
            exit();
     }

为了在每个 Keyup 事件的每个帖子上重新生成 CSRF 令牌可能有点过火了。但这是另一个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    相关资源
    最近更新 更多