• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to use POST while keeping CSRF as true

#1
Hi,


I am using Codeigniter 3.1.1. And I want to submit the form using AJAX with CSRF protection enabled.
So, I have set $config['csrf_protection'] = TRUE in config.php. But the POST request does not work and gives error as 'Forbidden' as I set the CSRF variable as TRUE.

Can anybody help how can I use POST request while keeping $config['csrf_protection'] as TRUE.

Below is the PHP code for reference:
Code:
<?php

$attributes = array(

'role' => 'form', 

'id' => 'country_actvity_search'

);

echo form_open('', $attributes);

?>

<div class="row">

<div class="col-md-4">

<div class="form-group">

<?php

echo form_label('Select Country:', 'country_name');

$data= array(

'class' => 'form-control',

'id' => 'country_name',

'name' => 'country_name'

);



foreach ($country_overview as $res){

$options[$res->Country] = $res->Country;

};

echo form_dropdown($data, $options );

?>

</div>

</div>

<div class="col-md-4">

<div class="form-group">

<?php

echo form_label('Select Year:', 'country_year');

$data= array(

'class' => 'form-control',

'id' => 'country_year',

'name' => 'country_year'

);



$year = array(

'2017' => '2017'

);

echo form_dropdown($data, $year );

?>

</div>

</div>

</div>

<?php

$data = array(

'type' => 'submit',

'value'=> 'Search',

'class'=> 'btn btn-primary',

'name'=> 'Search'

);

echo form_submit($data); 



echo form_close();
?>


Below is the AJAX code for reference:
Code:
$(document).ready(function(){

$("#country_actvity_search").submit(function(e){   

e.preventDefault();

var country_name = $("select#country_name option").filter(":selected").val();

var country_year = $("select#country_year option").filter(":selected").val();

var url = "<?php echo base_url(); ?>user/country_actvity_search/";

var csrf_hash = "<?php echo $this->security->get_csrf_hash(); ?>";

$.ajax({

url: url,

method: 'POST',

data: { csrf_token_name : csrf_hash, country_name: country_name, country_year: country_year,  },

success:function(res)

{



$("#charts_country_report").html(res);





},

error: function (jqXHR, textStatus, errorThrown){

alert(errorThrown);

}

});

});
});

Thanks,
-Krati
Reply

#2
This has been asked and answered many times.

When you do an ajax post you need to read in the csrf hash and token from the form hidden field values and submit that with the ajax post.

When you return your results, you also need to return the new token value. Then update your form with the new value (as it has now changed).

Then every ajax call and your form will have or read the same, current, token value.

There are lots of code samples on the forum.

Hope that helps,

Paul.

PS Do not be tempted to turn off the CSRF for your ajax calls. Once you have this working it becomes a trivial (albeit tedious) matter to do for all your ajax posts. If possible, use a get and then the CSRF is not regenerated.
Reply

#3
This need not be tedious. Since you are using form_open() much is greatly simplified mostly because doing so adds the hidden field with the CSRF token and hash to the form. This field can easily be included in the data posted by $.ajax.

The easiest way to proceed is change your JavaScript so that Instead of getting the values of the form inputs individually use the JQuery method .serializeArray()

Here would be my preferred way to go about this.

Code:
$(document).ready(function () {
    var  baseURL = window.location.protocol + "//" + window.location.hostname;

    $("#country_actvity_search").submit(function (e) {
        e.preventDefault();
        var postData = $( this ).serializeArray();
        var url = baseURL+'/user/country_actvity_search';

        $.ajax({
            url: url,
            method: 'POST',
            data: postData,
            success: function (res)
            {
                $("#charts_country_report").html(res);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
            }
        });
        
    });
});

I try to avoid executing PHP code in the JavaScript. Trying to do so almost always turns into a "gotcha" in my experience. That's why I combine these two lines to create the URL for the ajax call

Code:
var  baseURL = window.location.protocol + "//" + window.location.hostname;
//and later
var url = baseURL+'/user/country_actvity_search';
Reply

#4
(12-28-2017, 02:24 PM)Thanks for your helps. :)I have made the changes as per your comment. But the thing is, my value does not pass in \success' function and still gives 'forbidden' as error.Thanks, -Krati Wrote: Hi Dave,
dave friendThis need not be tedious. Since you are using form_open() much is greatly simplified mostly because doing so adds the hidden field with the CSRF token and hash to the form. This field can easily be included in the data posted by $.ajax.

The easiest way to proceed is change your JavaScript so that Instead of getting the values of the form inputs individually use the JQuery method .serializeArray()

Here would be my preferred way to go about this.

Code:
$(document).ready(function () {
    var  baseURL = window.location.protocol + "//" + window.location.hostname;

    $("#country_actvity_search").submit(function (e) {
        e.preventDefault();
        var postData = $( this ).serializeArray();
        var url = baseURL+'/user/country_actvity_search';

        $.ajax({
            url: url,
            method: 'POST',
            data: postData,
            success: function (res)
            {
                $("#charts_country_report").html(res);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
            }
        });
        
    });
});

I try to avoid executing PHP code in the JavaScript. Trying to do so almost always turns into a "gotcha" in my experience. That's why I combine these two lines to create the URL for the ajax call

Code:
var  baseURL = window.location.protocol + "//" + window.location.hostname;
//and later
var url = baseURL+'/user/country_actvity_search';
Reply

#5
Some troubleshooting tips:
  1. Make sure that you are actually executing the revised JavaScript by clearing the browser cache.
  2. Use your browser's Developer Tool to examine the request header of the post. You should be able to see the CSRF values being posted
  3. If you use $config['csrf_regenerate'] = TRUE; try setting it to FALSE until you figure out if that is the reason for the 403..

If you are using $config['csrf_regenerate'] = TRUE; then you will have to change what you return and how it is used in the success function. Let us know if you need help with that.
Reply

#6
Thanks for your help.
For point number 2, this is what I can see in developer tool:

General

Request URL:http://localhost/Projects/New_folder/dashboards/user/country_actvity_search
Request MethodTongueOST
Status Code:403 Forbidden
Remote Address:[::1]:80
Referrer Policy:no-referrer-when-downgrade


Response Headers

Connection:Keep-Alive
Content-Length:1131
Content-Type:text/html; charset=UTF-8
Date:Tue, 02 Jan 2018 05:58:20 GMT
Keep-Alive:timeout=5, max=99
Server:Apache/2.4.28 (Win32) OpenSSL/1.0.2l PHP/7.1.10
Set-Cookie:csrf_cookie_name=08af56109abf30e2787847894cfcc24c; expires=Tue, 02-Jan-2018 07:58:20 GMT; Max-Age=7200; path=/; domain=http://localhost/Projects/New_folder/dashboards/
X-Powered-ByTongueHP/7.1.10


Request Headers

Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Connection:keep-alive
Content-Length:86
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Cookie:ci_session=1e4emamhsuvf2ho1pjc5tnavaiup1243
Host:localhost
Origin:http://localhost
Referer:http://localhost/Projects/New_folder/dashboards/user/country_overview
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
X-Requested-With:XMLHttpRequest


Form Data

csrf_token_name:cdbbad48a99402d377961d7348a1bc4c
country_name:Sweden
country_year:2017



Also, I have kept $config['csrf_regenerate'] = FALSE;

Can you help with the issue.

Thanks,
-Krati
Reply

#7
You can get csrf_token_name and csrf_hash code and pass these parameter in POST

var csrfName = '<?php echo $this->security->get_csrf_token_name(); ?>',
    csrfHash = '<?php echo $this->security->get_csrf_hash(); ?>';
Reply

#8
You all should be using https:// now with Chrome...
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#9
The csrf data is clearly being sent to the server as this shows.

(01-01-2018, 11:21 PM)kratisalgia Wrote: Form Data

csrf_token_name:cdbbad48a99402d377961d7348a1bc4c
country_name:Sweden
country_year:2017

But on the headers you show $config['csrf_regenerate'] seems to be set = TRUE. I say this because the value of csrf_cookie_name in "Form Data" is not the same as in the "Response Headers". The values will be the same when $config['csrf_regenerate'] = FALSE;

Maybe some other configuration issue will be spotted if you share the $config settings you are using in Cookie Related Variables and Cross Site Request Forgery variables.
Reply


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.