1

I have two links on my html page :

<a id="1" onclick="like(this.id)">first</a> <a id="2" onclick="like(this.id)">Second</a> 

My JS is the following :

function like (id) { $.ajax({ type:'POST', data: { func: 'getNewLocations', '<?php echo $this->security->get_csrf_token_name(); ?>': '<?php echo $this->security->get_csrf_hash(); ?>', message:id }, url:'<?php echo base_url();?>index.php/Category/like', success: function(result, statut) { if (result == 'add') { //do something } else if (result == 'remove') { //do something } } }); } 

And the php method is the following (just for the example):

public function like() { echo 'add'; } 

When I click at first on the link 1, the ajax request works fine, the server answers 'add'. But when I click on the link 2, I have a 403 error. Even more surprising, when I click at fisrt on the link 2, it works but then the link 1 doesn't. I work with codeIgniter.

Any idea of why and how solve it ? Thanks

6
  • add this in function event.preventDefault(); after this line function like (id) { Commented Nov 9, 2016 at 14:27
  • I dont see you returning a new csrf token name/value to use in the next server request, so your subsequent requests get denied Commented Nov 9, 2016 at 14:30
  • It doesn't change anything.. Commented Nov 9, 2016 at 14:30
  • @PatrickEvans how can I do that ? Commented Nov 9, 2016 at 14:31
  • @devpro, that is not needed if the anchor tag doesnt actually have an href attribute. When there is no href attribute it doesnt do a navigation action onclick Commented Nov 9, 2016 at 14:32

3 Answers 3

2

Since it seems you are using a CSRF token to validate requests any request that sends an invalid token is going to get denied.

When you click either anchor for the first time you use up that token. So in order to make an additional request you need to get a new token back in the response and use it instead of the old one.

You just send back your data value, "add" in this case, with your csrf values: get_csrf_token_name() and get_csrf_hash()

Instead of sending back just plain text you could send back JSON value that contains the values, for example

php script

function like(){ $output = new stdClass; $output->csrfName = $this->security->get_csrf_token_name(); $output->csrfHash = $this->security->get_csrf_hash(); $output->data = "add"; echo json_encode($output); } 

In javascript

//Initial csrf values var csrfName = '<?php echo $this->security->get_csrf_token_name();?>'; var csrfHash = '<?php echo $this->security->get_csrf_hash();?>'; function like (id) { //create data object here so we can dynamically set new csrfName/Hash var data = { func:'getNewLocations', message:id }; data[csrfName] = csrfHash; $.ajax({ type:'POST', data: data, //dataType tells jQuery to expect JSON response dataType:"json", url:'<?php echo base_url();?>index.php/Category/like', success: function(result, statut) { if(result.csrfName){ //assign the new csrfName/Hash csrfName = result.csrfName; csrfHash = result.csrfHash; } if (result.data == 'add') { //do something } else if (result.data == 'remove') { //do something } } }); } 

Note if you are supporting ECMAScript 2015 capable browsers you could use computed keys to set your csrf values within the data object initializer

 $.ajax({ type:'POST', data: { [csrfName]:csrfHash, func:'getNewLocations', message:id }, 
Sign up to request clarification or add additional context in comments.

2 Comments

I did what you said, but i still have the first click working but not the second one, with the same error 403
@LucasPierrat, are you sure you implemented it correctly? Have you verified that a new token is being received and then being sent out with each new request? Have you checked your server logs to see if they log a reason for the 403?
1

After the first submit the csrf token is no longer valid, you have two options.

You can either set the following in config.php

$config['csrf_regenerate'] = FALSE; 

or update the csrf token on the page.

Comments

0

For Codeigniter 4

First, go to app/Config/Security.php

change

public $regenerate = true; 

To

public $regenerate = false; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.