您好我正在寻找在使用ajax提交表单时在codeigniter中重新生成csrf令牌的过程。我希望在没有页面刷新的情况下重新生成令牌。有没有办法做到这一点。
答案 0 :(得分:2)
根据具体情况,我在不同时间使用两种解决方案。
<强> 1。稍微凌乱的方式,但建议
获取控制器中的令牌名称和哈希值,并将其设置在页面上的某个位置作为数据字段(无论您选择哪个位置)。例如
// get the data and pass it to your view
$token_name = $this->security->get_csrf_token_name();
$token_hash = $this->security->get_csrf_hash();
// in your view file, load it into a div for instance
<div id="my_div" data-token="<?php echo $token_name; ?>" data-hash="<?php echo $token_name; ?>"
现在在您的js ajax代码中,您只需读取“my_div”中的数据值即可获得适合您的ajax调用的数据。
如果你的页面上有一个真实的表单会更容易,在这种情况下,而不是使用一些div,只是不要在表单上使用form_open,而是自己创建隐藏的表单字段,这样你就可以阅读它很容易通过js。
<input type="hidden" id="my_data" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />
这是重要的一点:当然在发送帖子数据后,您需要刷新令牌哈希值(在表单输入字段或div数据中,但是您选择这样做) 。编写一个名为'refresh_csrf_data'的js函数,并使用'GET'获取数据并更新字段。只要你完成了一个ajax帖子,就可以调用这个函数。
因此,每次ajax调用都会读取令牌数据,进行调用,然后刷新准备好下次调用的令牌数据。
<强> 2。简单但不太安全
或者,您可以使用
为ajax调用禁用CSRF $config['csrf_exclude_uris'] = array('controller/method');
在CSRF设置的配置文件中。
第3。更简单但也更不安全,我不使用它 最后,您可以在每次提交时关闭重新生成CSRF哈希
$config['csrf_regenerate'] = FALSE;
但是,请谨慎行事。这可以让你接受某些类型的攻击。</ p>
最适合您的答案完全取决于页面类型,用法,用户是否在此时登录,是关键任务还是次要内容,是财务等等。
没有什么是完全安全的,所以它有时是妥协。就个人而言,我会在完全重新生成时使用CSRF,在URI中没有例外,并在需要时重新加载令牌和哈希数据。它似乎很复杂,而且要解释一下,但是一旦你做了一次,在你需要的时候一次又一次地做起来真的很容易,你的网站将比仅仅避免其他选项的问题安全得多。 / p>
答案 1 :(得分:0)
我发现使用form helper函数可以更好地与Codeigniter一起使用 CSRF并停止抛出CSRF错误如果使用普通的html输入 将继续抛出CSRF错误。
这是一个AJAX示例
<?php echo form_open('controller/example', array('id' => 'form-login'));?>
<?php
$username_array = array(
'name' => 'username',
'id' => 'username',
'class' => ''
);
echo form_input($username_array);
?>
<?php
$password_array = array(
'name' => 'password',
'id' => 'password',
'class' => ''
);
echo form_password($password_array);
?>
<?php
$submit_array = array(
'name' => 'submit',
'id' => 'submit',
'class' => '',
'value' => 'Submit',
'type' => 'submit'
);
echo form_input($submit_array);
?>
<?php echo form_close();?>
<script type="text/javascript">
$('#submit').click(function(e){
e.preventDefault();
var post_data = {
'username' : $('#username').val(),
'password' : $('#password').val(),
'<?php echo $token_name; ?>' : '<?php echo $token_hash; ?>'
};
$.ajax
({
type: 'post',
url: "<?php echo base_url('example/');?>",
data: post_data,
dataType: 'json',
success: function(response)
{
if (response['success'] == true) {
// Success
} else {
// Error
}
}
});
});
</script>
实施例
public function index() {
$data['token_name'] = $this->security->get_csrf_token_name();
$data['token_hash'] = $this->security->get_csrf_hash();
$this->load->view('login_view', $data);
}
public function example() {
$data = array('success' => false, 'messages' => array());
$this->form_validation->set_rules('username', 'username', 'required');
$this->form_validation->set_rules('password', 'password', 'required');
if ($this->form_validation->run() == false) {
foreach ($_POST as $key => $value) {
$data['messages'][$key] = form_error($key);
}
} else {
$data['success'] = true;
}
echo json_encode($data);
}
答案 2 :(得分:0)
如果它没有在会话中,那么你的控制器将是这样的
public function save_date() // or whatever function you like
{
$regen_token = $this->security->get_csrf_hash();
$data = array(
"data" => $this->input->post('datas'),
);
$insert = $this->w_m->save($data);
echo json_encode(array("regen_token" => $regen_token));
}
你的ajax中的将如下所示:
$.ajax({
url: "your url",
type: "POST",
data: { your data },
dataType: "JSON",
success: function(data)
{
$("name or id of your csrf").val(JSON.stringify(data.regen_token)).trigger("change"); // this will be the function that every post you'll request and it automatically change the value of your csrf without refreshing the page.
},
error: function(errorThrown)
{
console.log(errorThrown);
}
});
答案 3 :(得分:0)
在回调中添加一个csrf哈希数组。
答案 4 :(得分:0)
对我有用的解决方案是,当为每个请求启用CSRF时,后续的ajax发布是在由于令牌过期而导致请求失败时,在AJAX成功中发出GET请求。然后有一个隐藏字段,该字段会继续用最新令牌更新,如果在发出请求时令牌已过期,则您进行GET REQUEST来获取最新令牌,然后在提交表单或提交POST请求的函数上触发click事件,这意味着该功能必须传递“ this”或ID作为参数的一部分。这使用户无法在后台实现续签令牌的过程