CSRF Token Valid on First Submit in Ajax - Codeigniter - php

Below is my code and how i submit my data using the Ajax. On first submit, the data is posted successfully, however, when i try again, it fails which i suspect is from an invalid csrf since a new token may be generated. How can i solve this problem ?
$('#icon').on('click', '#test', function() {
var ids = $(this).data('id');
var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
var dataJson = { [csrfName]: csrfHash, ids: ids };
$.ajax({
url: '<?php echo base_url('client/data'); ?>',
type: 'POST',
data: dataJson,
}).done(function (result) {
});
});

I have same problem and i solve this by refreshing csrf token. New csrf token get in ajax response form server and replace it old token which is store in form hidden field and when you submit again use the new token.It solve my problem hopes your problem also fixed by doing this, for more use this link https://codeigniter.com/user_guide/libraries/security.html

The solution that worked for me when $config['csrf_regenerate'] = TRUE is that for subsequent ajax post when CSRF is enabled for every request is to make a GET request in AJAX Success when request fails because token has expired. Then have a hidden field that continue to be updated with latest token and if at the time of making request it has expired you make a GET REQUEST to fetch latest TOKEN and then evoke click event on function that submits form or function making POST request which means the function has to be passed "this" or ID as part of parameter.This makes the user not to realize the process of renewing token in the background

Related

How to retrieve and display AJAX response on WordPress

I have built a custom registration form which creates a new WordPress user account and redirects the user to the /my-account/ area on completion. The issue I have is that I am not displaying any information on the front-end when the form is not submitted correctly i.e. the account creation process failed.
I am trying to log the AJAX response to console so I can see what I'm working with but it appears I'm not getting a response at all.
The code that I currently have in place:
<script>
jQuery('form[name="form-new-customer"]').on('submit', function() {
let form_data = jQuery(this).serializeArray();
jQuery.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type: 'post',
data: form_data,
success: function(response) {
console.log(response);
window.location.replace('<?php echo get_site_url(); ?>/my-account/');
},
fail: function(err) {
console.log(err);
}
});
return false;
});
</script>
As you can see, I have a redirection for 'success' but this redirection also happens when the account user process fails. I'm assuming it's always a success because the AJAX request was carried out correctly and it's not able to know whether or not the PHP function ran or not?
I need to somehow get the User ID (if an account is created) and then check if it exists. This would determine if the function was successful or not. If not, then I can display a message to the end user?

Avoid error 403 in codeigniter on a second POST request

I can't understand why I cannot do more than one request without refreshing page.
Any request is working fine, but If I need to execute another request (don't mind if it's the same or not)... I can't! I need to refresh the page to do a new request, otherwise, I'll get error 403.
All the code is working, just, any request is finishing with refreshing the page. I don't like that because I consider it's not professional.
What do I need to change in codeigniter to allow more than one request without refreshing the page?
update from comment: I use csrf protection and I don't want to disable it.
#Vickel this is one of the requests (all of them is almost the same, just url and data)... there's no form.
function set_tracking(order_id)
{
$.ajax({
type: "POST",
data: {
order_id: order_id
},
url: trackingURL,
beforeSend: function() {
$('.lds-default').removeClass('hidden');
},
success: function (response) {
console.log(response);
if(response.error)
{
show_form_errors(lang['productions_error_not_set_tracking']);
} else {
$('#set_tracking .modal-title').html(lang['productions_set_tracking_title']);
$('#set_tracking').modal('show');
$('#set_tracking #order_id').val(order_id);
}
},
error: function (event) {
if (event.status !== 401) {
show_form_errors(lang['companies_error_deleting_segment']);
}
},
complete: function() {
$('#confirm_message').modal('hide');
$('.lds-default').addClass('hidden');
}
});
}
You're encountering an expired CSRF token. There's multiple ways around this (each with different complexity and security levels)
1.- Disable CSRF altogether (not recommended unless all your forms live within a secure area where everyone is logged in and there's no way to get a cross-domain request, which is unlikely.
2.- Define exceptions for the CSRF functionality. In application/config/config.php you'll find an array called $config['csrf_exclude_uris'] where you can add all the controller/method pairs for which you wish the CSRF checks to not be enforced
3.- Disable CSRF regeneration. In application/config/config.php you could set $config['csrf_regenerate'] to false. This will prevent the CSRF token to be regenerated after each request, which would allow you to make more than one submission without being blocked by the CSRF check
4.- Manually get a regenerated token after the first submission and pass it along with the second submission. This is the most secure way to address your issue, but the most complex. You can read about this in depth in the Codeigniter's Security Class documentation here
in order to manually regenerate the CSRF token you can do the following:
create an hidden input field in your view, which stores your csrf token
in your controler, you create a new token and send it back with your ajax response
in your ajax success function, you update your hidden input field
now you are ready for sending a new request
view:
<?php
$csrf = array(
'name' => $this->security->get_csrf_token_name(),
'hash' => $this->security->get_csrf_hash()
);
?>
<input type="hidden" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />
javascript:
tn='<?php echo $this->security->get_csrf_token_name(); ?>';
th=$('input[name="'+tn+'"]').val();
csfrData={tn:th};
$.ajax({
type: "POST",
dataType:json,
data: {
order_id: order_id,
csrf:csfrData // send current token
},
//etc...
success: function (response) {
// update hidden input field with new token
$('input[name="'+response.csrf.csrf_name+'"]').val(response.csrf.csrf_hash)
// etc
}
})
controller:
function your_tracking_url(){
$data['yourdata']=array() // whatever you return
$data['csrf']=$this->get_csrf();
echo json_encode($data);
}
function get_csrf(){
// creating a new token
$csrf=array('csrf_name'=>$this->security->get_csrf_token_name(),'csrf_hash'=>$this->security->get_csrf_hash());
return $csrf;
}
you might need to adapt this a little bit, but it shows the concept how manual csrf token regeneration works

Cached Ajax Call

I have a problem in the application I am building. And I have read many threads about the similar problem and have applied the suggestion given in those threads. However, the problem persists hence I write this.
The setup for is as follows:
I have the 3 php files: index.php, step_one.php and calculation.php.
From the index.php, I successfully load the step_one.php via the Ajax call which is as follows:
$(document).ready(function () {
var nocache = Math.random() * new Date().getTime() + Math.random();
$("#bookings").click(function () {
$.ajax({
url: 'step_one.php?cach='+nocache,
type: 'post',
cache: false,
success: function (data) {
$("#contentLeft").html(data);
}
});
});
});
Note: step_one.php is the html form.Then in step_one.php, I enter the data in the form and send the form data to calculation.php via another Ajax call that is as follows:
$("#viewprice").click(function () {
var nocache = Math.random() * new Date().getTime() + Math.random();
$.ajax({
url: 'calculate_quote.php?cache=' + nocache,
type: 'post',
dataType: 'json',
cache: false,
data: $("#stepOneForm").serialize(),
success: function (data) {
console.log(data);
$(".quote").append(data);
$(".quote").show();
document.getElementById("price").value = data;
}
});
});
The calculation.php file, calculates the price based on the data it receives and return the json to step_one.php. This is how I return json from calculation.php:
header('Content-Type: application/json');
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1.
header('Expires: 0'); // Proxies.
echo json_encode($data);
Note: The first time I click the #viewprice button, the price is correctly and successfully return to step_one.php. However, when in step_one.php I enter new data and re-click the #viewprice button, nothing is returned from calculation.php. And when I inspect the Network data, I see the calculation.php gets duplicated there and only the first Ajax call will the data in its response.
And this running in the local machine in xamp.
Would you please assist? What am I doing wrong here?
I found the bug that was giving me headache. It was a logical error.
Background
I use tokens in my forms for security reason. So for each form, I generate a token on page load and store it in the session. Then when the form sends its data (including the token), I first check if the received token is in the session - if the token is found, I then use the receives values and use them to compute $data which I then pass it to json_encode function. After the token is found, I delete it.
So, the calculation.php was not cached as my Ajax code is correct. Instead, the problem was when I resend the form data for re-calculation. During resend, the token in the session has already been deleted; therefore, the token I send with the form data could not be found in the session. Hence, data not computed and nothing is return.
Caching Ajax POST requests
Think the above link will be useful >>>

Ajax session timeout

Situation :
My web application is password protected.For each http request we make to server, it is being checked against session existence. If session has been expired then the user is forwarded to login page.
This goes fine for http requests. But if it is an AJAX request, then just like http request, if session has been expired, it is also forwarded to login page.
Problem :
if we are directly showing AJAX response in browser, then in place of our expected response will show the login page content in your browser.And if you would be fetching data of any expected format, then it would throw JavaScript error.
My Code :
<script>
function details() {
var xyz = document.getElementById("name").value;
// Returns successful data submission message when the entered information is stored in database.
var dataString = 'name=' + xyz;
// AJAX code to submit form.
$.ajax({
type: "POST",
url: "user.php",
data: dataString,
cache: false,
success: function(html) {
document.getElementById("content").innerHTML=html;
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
if (XMLHttpRequest.status === 401) {
location.href = 'index.php';
}
}
});
return false;
}
</script>
on Session time out when i call Ajax request through my code. It loads the login.php content into the current page instead of forwarded the user to login Page.
Guide me where i am doing something wrong.
Thanks.
If your are working with multiple ajax request, then you can use jquery ajaxComplete function.
This function run every time after ajax call but before the success or failure function attached to that ajax event.
eg for this code is :
jQuery("body").ajaxComplete(
function(event, request, options) {
if (request.responseText == "login_required") {
window.location.href = "login.php";
}
}
);
And on your server side, you just have to check if the request is an ajax request and if user is not logged in, just print "login_required" and stop the execution of code(exit the code).
User will redirect to login.php page

Preventing CSRF and XSRF Attacks for jQuery $.post

I was recently hit by a simple CSRF attack and realized a lot of my ajax scripts are open. These are accessed on my site with $.post().
Is there a way to automatically add a PHP token to all of these or do I need to go through and do it all one-by-one?
Using bwoebi's answer, I found a slightly better solution. jQuery has a built in setup function for ajax.
<script>var token ="<?= $_SESSION['token'] ?>";</script>
<script>
jQuery.ajaxSetup({
data: {
token: token
}
});
</script>
This will add your token to every jQuery request!
An idea would be to replace your $.post function:
jQuery["post"] = function (url, data, callback, type) {
data["token"] = token; // where token is a global variable
// you write in a <script> 'var token = <?php echo $_SESSION["token"]; ?>;'
return jQuery.ajax({ // copied from the jQuery code
url: url,
type: "POST",
dataType: type,
data: data,
success: callback
});
};
So you only have to add this little code after including the jq-lib.

Categories