Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Rest for AJAX, CSRF token and AJAX request
  • Hi,

    Few questions:

    1) I have decided to use the Rest Controller to handle my AJAX request. I find it very powerful, hence my questions: 
    • do I still have to use Input::is_ajax() check in the rest controller handling it?
    • I'm able to request my controller using multiple extensions... JSON, XML etc. Cool feature, however I do only use the JSON, but should I restrict other extensions then? if ( Input::extension() !== 'json' ) [...]...
    • When I need to return error to AJAX, I simply change the response http status code. Is this correct or should I have used something else (I don't think so, just want to make sure)? $this->response('Error', 400);
    2) I'm autoloading CSRF for all of my requests:

            'csrf_autoload'            => true,
    // 'csrf_autoload_methods' => array('post', 'put', 'delete'),
    // 'csrf_bad_request_on_fail' => true,
    'csrf_auto_token' => true,
    'csrf_token_key' => '_token',
    'csrf_expiration' => 1 * 60 * 60,
    Thats why it doesn't work with AJAX. ("CSRF validation failed, Possible hacking attempt detected!") because new token gets generated. I know I should validate on form submit, however this is not possible since I'm uploading & validating images into my form widget. How should I handle it properly?

  • 1:
    • If you want to block non-ajax access, yes.
    • You can force a return format by setting the $format propery in your controller to "json". This will disable the format autodetection.
    • That depends on your needs. In general, you use the HTTP status to return the status of the entire response. Our API's return a class with a fixed structure, that contains both a section for messages, and for the response payload, instead of only the payload.
    2:

    For ajax clients you can use https://fuelphp.com/docs/classes/security.html#/method_js_fetch_token to fetch the current token before you submit your data. For forms you can use the solution given in the example to make sure the csrf token in the forum is valid.
  • Yes I do call Security::js_fetch_token() before Form::close(). In the AJAX call I do:


    data = new FormData();
    data.append( '_token', fuel_csrf_token() );
    data.append( 'image',
    images );
    $.ajax( {
    data: data,
    datatype: 'JSON',
    type: 'POST',
    url: controller.editor.data( 'image-handler-url' ),
    cache: false,
    contentType: false,
    processData: false,
    success: function( url ) {
    controller.editor.insertImage(url)
    },
    error: function( r ) {
    alert( r.responseJSON );
    },
    } );


    Now AJAX calls are working. But my problem is when I finally submit the form, I'm getting the "CSRF validation failed, Possible hacking attempt detected!" notice. If I wont upload, form submits without problems.
  • Your token variable name is configured as "_token"?

    You no only get this error when the token is wrong, but also if the token can not be found in the input. It is configured in app/config.php, security.csrf_token_key. If you haven't set it, the default is "fuel_csrf_token".

    If you want to check, set autoload to false, and dump Input::all() in your contrroller to see exactly which input has been pasted.
  • Yes, my token name is configured as "_token" (I gave the entire CSRF config above).

    It really appears that something wrong is happening on the fly, since _token is always in the input, but it appears to change if an AJAX call to the rest controller is being made to upload the image. Expiration is set to one hour right now. Very odd.

    So, if I load a fresh page and simply submit the form - works fine.
    If I load a fresh page and change some value on the input then submit - works fine.
    If I load a fresh page and use my JS AJAX widget to upload an image, then submit - error is being thrown.

    I do pass the token to the AJAX call as well as you could see above and that works fine, token is being validated in the rest controller to upload a file. It's however not valid when it comes to the default page controller.

    Using Fuel 1.8. 


  • If you use the javascript functions, you always have the correct and valid token as stored in the cookie.

    You write "upload an image, than submit". That sounds like two POST requests. If that is the case, the first request will invalidate the cookie, so the second will fail if you don't use the javascript function in between the two to update the _token value again.
  • Exactly.. Thats why I'm asking what to do in this case :-)
  • Make sure the _token field is updated before every POST?
  • Yep I thought there is any way to not update the token under certain circumstances. This is a little bit annoying to update the token field on each AJAX request.

    It will be probably a better idea to use the Javascript fuel_csrf_token() method to simply update the _token field if exists, on each form submit. This way I wouldn't need multiple widgets sending AJAX POST requests doing the same thing.
  • I get your point. 

    I read in the config comments: "Expiry of the token in seconds. If zero, the token remains the same for the entire user session.".

    However, if you look at the code, it isn't implemented like that. Instead, this value is used as the expiry of the token cookie, and zero just means "expire at end of session. The token always expires after a check.

    I'll see what I can come up with.
  • Neat! Thanks a ton :-)
  • You're welcome. Let me know if it needs more tweaking.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion