How to Send AJAX request with CSRF token in CodeIgniter
In CodeIgniter, CSRF security isn't empowered as a matter of course.
In the event that it is been empowered, at that point CodeIgniter creates a hash for every dynamic client and this is utilized to confirm the solicitation.
Require to send the hash with the AJAX demand else, it gives mistake – "The activity you have mentioned isn't permitted.".
Right now, show how you can empower CSRF insurance and recover hash for next AJAX solicitation and pass hash in AJAX demand in the CodeIgniter venture.
- Table structure
Right now, am utilizing clients table and included a few records –
CREATE TABLE `users` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` varchar(80) NOT NULL,
`username` varchar(80) NOT NULL,
`gender` varchar(10) NOT NULL,
`email` varchar(80) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- Setup
Empower CSRF assurance –
Open application/config/config.php file and update the values of $config['csrf_protection'], $config['csrf_token_name'], and $config['csrf_regenerate'] like this –
$config['csrf_protection'] = TRUE; // Enable CSRF
$config['csrf_token_name'] = 'csrf_hash_name'; // Token name (You can update it)
$config['csrf_regenerate'] = TRUE; // Set TRUE to regenerate Hash
- Set TRUE the $config['csrf_protection'], this will empower CSRF.
- You can change the estimation of $config['csrf_token_name'] default it is set to 'csrf_test_name'. I transformed it to 'csrf_has_name'. This name is utilized in AJAX solicitation to pass the hash.
- Set TRUE the $config['csrf_regenerate'] in the event that you need to recover CSRF hash after every AJAX demand in any case set it FALSE.
Open application/config/database.php and characterize the Database association.
$db['default'] = array(
'dsn' => '',
'hostname' => 'localhost',
'username' => 'root', // Username
'password' => '', // Password
'database' => 'tutorial', // Database name
'dbdriver' => 'mysqli',
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => (ENVIRONMENT !== 'production'),
'cache_on' => FALSE,
'cachedir' => '',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
'encrypt' => FALSE,
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
);
Default controller
Open application/config/routes.php and alter default_controller incentive to User.
$route['default_controller'] = 'User';
Burden Database
To get to the MySQL database require stacking database library.
Open application/config/autoload.php and include the database in libraries exhibit().
$autoload['libraries'] = array("database");
- Model
Make a Main_model.php record in the application/models/registry.
Make getUserDetails() technique which takes a solitary parameter.
Check if $postData['username'] is set or not. Whenever set at that point get a record from clients table where username=$postData['username'].
Return the $response Array.
Completed Code
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Main_model extends CI_Model {
function getUserDetails($postData){
$response = array();
if(isset($postData['username']) ){
// Select record
$this->db->select('*');
$this->db->where('username', $postData['username']);
$q = $this->db->get('users');
$response = $q->result_array();
}
return $response;
}
}
- Controller
Make User.php document in application/controllers/registry.
Make 2 strategies –
- index – Load url partner and user_view see.
- userDetails – This strategy is utilized to deal with the AJAX solicitation and return a reaction.
Peruse POST esteems and allot in $postData. Burden Main_model Model and call getUserDetails() technique where pass $postData.
Dole out return an incentive in $data and read the new CSRF hash by calling $this->security->get_csrf_hash() for next AJAX ask for and appoint in $data['token'].
Return $data Array in JSON position.
Completed Code
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class User extends CI_Controller {
public function index(){
// load base_url
$this->load->helper('url');
// load view
$this->load->view('user_view');
}
public function userDetails(){
// POST data
$postData = $this->input->post();
// load model
$this->load->model('Main_model');
// get data
$data = $this->Main_model->getUserDetails($postData);
// Read new token and assing in $data['token']
$data['token'] = $this->security->get_csrf_hash();
echo json_encode($data);
}
}
- View
Make user_view.php document in application/sees/catalog.
Make a book component and store token name which is indicated in application/config.php record in name trait utilizing <?= $this->security->get_csrf_token_name(); ?>. Store CSRF hash in the component by calling <?= $this->security->get_csrf_hash(); ?>.
Included some client names in the <select > <option>. Utilized username in the <option > esteem.
To show chosen client subtleties made <span > components.
Script –
Characterize change occasion on #sel_user selector.
Peruse name quality of .txt_csrfname selector and relegate in csrfName variable. Dole out .txt_csrfname selector esteem in csrfHash variable.
Dole out chosen alternative incentive in username variable.
Send AJAX POST solicitation to '<?=base_url()?>index.php/User/userDetails' the place pass {username:username,[csrfName]:csrfHash } as information.
Here, hash will pass like – [csrfName]: csrfHash.
On effective callback read the token from reaction and update the .txt_csrfname selector esteem.
Circle on the response[0] and update <span > components content.
Completed Code
<!doctype html>
<html>
<head>
<title>How to Send AJAX request with CSRF token in CodeIgniter</title>
</head>
<body>
<!-- CSRF token (Here, name is 'csrf_hash_name' which is specified in $config['csrf_token_name'] in cofig.php file ) -->
<input type="text" class="txt_csrfname" name="<?= $this->security->get_csrf_token_name(); ?>" value="<?= $this->security->get_csrf_hash(); ?>"><br>
Select Username : <select id='sel_user'>
<option value='yssyogesh'>yssyogesh</option>
<option value='sonarika'>sonarika</option>
<option value='vishal'>vishal</option>
<option value='sunil'>sunil</option>
</select>
<!-- User details -->
<div >
Username : <span id='suname'></span><br/>
Name : <span id='sname'></span><br/>
Email : <span id='semail'></span><br/>
</div>
<!-- Script -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type='text/javascript'>
// baseURL variable
var baseURL= "<?= base_url();?>";
$(document).ready(function(){
$('#sel_user').change(function(){
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // Value specified in $config['csrf_token_name']
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
// Username
var username = $(this).val();
// AJAX request
$.ajax({
url:'<?=base_url()?>index.php/User/userDetails',
method: 'post',
data: {username: username,[csrfName]: csrfHash },
dataType: 'json',
success: function(response){
// Update CSRF hash
$('.txt_csrfname').val(response.token);
// Empty the elements
$('#suname,#sname,#semail').text('');
// Loop on response
$(response[0]).each(function(key,value){
var uname = value.username;
var name = value.name;
var email = value.email;
$('#suname').text(uname);
$('#sname').text(name);
$('#semail').text(email);
});
}
});
});
});
</script>
</body>
</html>
- Conclusion
On the off chance that you would prefer not to recover hash for each AJAX, at that point set FALSE to $config['csrf_regenerate'] in config.php document. Right now, new hash will be created by the CSRF expiry time set.
