Iframe causes Can't Verify CSRF Token Authenticity n Rails
Asked Answered
I

5

5

I have a webapp that is loaded through an iframe using phonegap 2.3.0 for Windows Phone 8 SDK. The problem with loading it through the iframe is that it causes Can't verify CSRF token authencity on the Rails side when I send a $.post() request.

I tried a couple of approaches such as overwrite the $.post() to use $.ajax() to setHeaderRequest with the token, and also $.ajaxSetup()

When I disable protect_from_forgery or verify_authenticity_token, the app loads correctly.

I believe the problem is caused because the webapp is located in another domain (cross domain issues) and csrf is simply trying to prevent clickjacking. Is there are way to bypass this problem?

Here is an example of how I am posting:

    $.post(url, {app: {played: tiles}, no: no}, function (response) {
      linkTo('#app_button', response['next']);
    });

Example:

    $.ajaxSetup({
      beforeSend: function(xhr) {
        xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').prop('content'));
      }
    });

Edit: I have been able to pass authenticity token as a parameter into my post request with the same error. I am starting to beleive the error is not cause by the token. What are other reasons why the error occurs?

Log:

[2539 - 2013/03/06 15:37:42] (INFO)   Parameters: {"app"=>{"played"=>"tiles"}, "no"=>"no", "authenticity_token"=>"yBpUImzjtKGIejh/WCekv/GCi1zjPirib22plqfLJ1Y="}
[2539 - 2013/03/06 15:37:42] (WARN) WARNING: Can't verify CSRF token authenticity
[2539 - 2013/03/06 15:37:42] (INFO) User agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920)
[2539 - 2013/03/06 15:37:42] (DEBUG)   User Load (1.8ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
[2539 - 2013/03/06 15:37:42] (DEBUG)   CACHE (0.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
[2539 - 2013/03/06 15:37:42] (DEBUG)   CACHE (0.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
[2539 - 2013/03/06 15:37:42] (WARN) Lost session [118.143.97.82] (/locations/1/games) - Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920)
[2539 - 2013/03/06 15:37:42] (DEBUG)   CACHE (0.0ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` IS NULL LIMIT 1
Iggy answered 6/3, 2013 at 5:42 Comment(0)
I
3

The answer is because of no P3P header which was blocking session storage. You need to add a P3P header to fix this.

Iggy answered 20/3, 2013 at 4:12 Comment(1)
There is a gem that enables rails to send P3P headers: github.com/carrot/p3pOrvie
M
1
   <input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>" >

Add this hidden field to your form. I had fixed the same issue like that of "Can't Verify CSRF Token Authenticity"

Marconigraph answered 6/3, 2013 at 5:49 Comment(3)
Its not a form, but a link. Is there another way to pass it?Iggy
may be this link helps you #3141541Marconigraph
Hmm.. the authenticity token is being passed into the parameter, but still getting the same error Parameters: {"app"=>{"played"=>"tiles"}, "no"=>"no", "authenticity_token"=>"ECVUG1gL8oHzjnlQgR95zxGMlWLvV2x/Ay7UO99LVv0="}Iggy
S
1

You can turn CSRF off for certain controller actions. You can make a new action (let's say iframe) for the purpose of the AJAX call and add in the controller:

skip_before_filter :verify_authenticity_token,  :only => [:iframe]
Solstice answered 6/3, 2013 at 5:51 Comment(0)
F
1

The problem is that you need to fetch a new token after an Ajax POST request because once a token is used it gets invalidated. Here is the code to do this:

In rails whenever a POST reply is sent add these parameters to the response:

def someMethod:
    result[:csrfParam] = request_forgery_protection_token
    result[:csrfToken] = form_authenticity_token
    render :json => result
end

Now on the JS side, in the success function of every POST method you can call this function:

var setCsrfToken = function(param, token) {
    if(param == null || token == null) {
        console.error("New CSRF param/token not present");
    }
    $("input[name='" + param + "']").val(token);
}

like this:

setCsrfToken(result["csrfParam"], result["csrfToken"]);

This function will reset all authenticity_token params in all POST forms so that the next request has a valid token. You need to make sure this happens in every POST call, otherwise you'll continue facing this problem.

Also, CSRF is not for preventing clickjacking, it's a separate attack altogether, where another website can make a user click a link that executes an action on your website with the user's session.

Failsafe answered 8/4, 2013 at 1:8 Comment(0)
T
0

@user1555300's answer is right just giving the details.

In application_controller.rb add this on top

before_filter :set_p3p

also add this method

private 
# for IE, Facebook, and iframe sessions
def set_p3p
  headers['P3P'] = 'CP="ALL DSP COR CURa ADMa DEVa OUR IND COM NAV"'
end

Make sure this is on the application_controller.rb not a regular controller.

Tanta answered 25/7, 2015 at 1:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.