У меня есть страница администратора с несколькими настройками, каждая настройка имеет разную форму на разных вкладках.
Я использую ajax и для сохранения данных, и пока у меня не было проблем с токеном csrf когда у меня была только одна форма на странице, или когда я отключил токен csrf.
При каждом запросе ajax в контроллере генерируется новый токен и отправляется обратно на ajax, который обновляет скрытое поле с name="csrf_token"
, но с другими идентификаторами.
После отправки первой формы все хорошо, но когда я пытаюсь отправить другую форму, токен csrf больше не работает, я получаю сообщение «Запрошенное действие запрещено». со страницей 403 в выводе консоли даже после того, как я перезагружаю страницу и пытаюсь отправить другую форму, которая не сработала.
Есть ли способ разместить несколько форм с защитой csrf на одной странице и как с этим справиться?
Вот примеры кода Формы с ajax
<form id="upload-icon" method="POST" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" id="csrf_token_1" value="<?php echo $this->security->get_csrf_hash(); ?>">
<input type="file" id="favicon_image" name="favicon_image" accept=".ico">
<button type="button" id="upload-icon-btn">Upload</button>
</form>
<form id="update-settings" method="POST">
<input type="hidden" name="csrf_token" id="csrf_token_2" value="<?php echo $this->security->get_csrf_hash(); ?>">
<input type="text" name="settings_one">
<input type="text" name="settings_two">
<input type="text" name="settings_three">
<button type="button" id="update-settings-btn">Update settings</button>
</form>
<script>
$(document).ready(function() {
var csrf_token = '';
// upload favicon form
$('#upload-favicon-form-btn').on('click', function(e) {
e.preventDefault();
var fd = new FormData();
var files = $('#favicon_image')[0].files[0];
fd.append('favicon_image', files);
var favicon = $('#favicon_image').val();
if (favicon == '') {
loadModal('Warning', 'Please select <strong>favicon.ico</strong> icon file.');
} else {
$.ajax({
type: 'POST',
url: '<?php echo base_url('admin/settings/upload_ico'); ?>',
data: fd,
contentType: false,
cache: false,
processData: false,
dataType: 'json',
success: function(response) {
csrf_token = response.csrf_token;
$('#csrf_token_1').val(csrf_token);
// messages output
},
error: function() {
// error message output
}
});
}
});
// update settings form
$('#update-settings-btn').on('click', function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '<?php echo base_url('admin/settings/update_settings'); ?>',
data: $('#update-settings').serialize(),
dataType: 'json',
success: function(response) {
csrf_token = response.csrf_token;
$('#csrf_token_2').val(csrf_token);
// messages output
},
error: function() {
// error message output
}
});
});
});
</script>
Контроллер настроек
public function update_settings()
{
$csrf_token = $this->security->get_csrf_hash();
$this->form_validation->set_rules('settings_one', 'Setting one', 'trim|required|xss_clean');
$this->form_validation->set_rules('settings_two', 'Setting two', 'trim|required|xss_clean');
$this->form_validation->set_rules('settings_three', 'Setting three', 'trim|required|xss_clean');
if ($this->form_validation->run()) {
if ($this->Settings_model->UpdateSettings($this->input->post('settings_one'), $this->input->post('settings_two'), $this->input->post('settings_three'))) {
$data = array(
'success' => true,
'message' => 'Settings updated.',
'csrf_token' => $csrf_token
);
} else {
$data = array(
'error' => true,
'message' => 'Settings was not updated.',
'csrf_token' => $csrf_token
);
}
} else {
$data = array(
'error' => true,
'settings_one_error' => form_error('settings_one'),
'settings_two_error' => form_error('settings_two'),
'settings_three_error' => form_error('settings_three'),
'csrf_token' => $csrf_token
);
}
echo json_encode($data);
}
public function upload_ico()
{
$csrf_token = $this->security->get_csrf_hash();
$favicon_upload_path = './upload/';
if (isset($_FILES['favicon_image']['name'])) {
$config['upload_path'] = $favicon_upload_path;
$config['allowed_types'] = 'ico';
$this->load->library('upload', $config);
if (!$this->upload->do_upload('favicon_image')) {
$data = array(
'error' => true,
'message' => $this->upload->display_errors(),
'csrf_token' => $csrf_token
);
} else {
$data = array(
'success' => true,
'message' => 'Favicon uploaded.',
'csrf_token' => $csrf_token
);
}
} else {
$data = array(
'error' => true,
'message' => 'No file selected.',
'csrf_token' => $csrf_token
);
}
echo json_encode($data);
}
Конфиг. php
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
$config['csrf_regenerate'] = TRUE;
$config['csrf_exclude_uris'] = array(
'admin/settings'
);