1

I am currently building a Rails backend for an iphone app. The iphone accesses special controllers which returns JSON that the iphone app parses and displays appropriately. The Rails app does have an admin panel and is used to insert new data for the iphone app. That authentication is controlled by Devise. Outside of that, there is no need to have complex authentication since the iphone app does not require any user information to function.

Here is where I'm stuck. I've added a controller where the user can submit feedback from the app. That feedback will be stored in the Rail's database. In order to do this, I have turned off protect_from_forgery by using skip_before_filter :verify_authenticity_token, :only => [ :create ] for that controller method. But by doing this, I understand that this creates a security problem. I also understand that I must create custom protection (such as a token) as per this answer, and this answer. My web searching has only found how to do this using Devise or through Oauth, but as I mentioned, there is no user authentication for the iphone. All I want to do is gap this one security hole, unless I'm missing something. I'm having trouble finding any articles regarding this particular situation.

Community
  • 1
  • 1
pacothelovetaco
  • 2,361
  • 3
  • 16
  • 12

2 Answers2

0

By default, Rails apps with :protect_from_forgery on include an authenticity token in the <meta> information about a page, like so:

<meta content="arBBP614zvMxug9+5ozHakrXhAaTNmQ9aBJ/Ehp3nl8=" name="csrf-token">

What you need to do is download a plain old html copy of your form, with :protect_from_forgery on, so this tag is generated. Then, once you have that HTML in a NSString* you can find the token like so:

    NSArray* firstArray = [htmlString componentsSeparatedByString:@"\" name=\"csrf-token\">"];
    NSArray* secondArray = [[firstArray objectAtIndex:0] componentsSeparatedByString:@"<meta content=\""];
    NSString* authToken = [secondArray objectAtIndex:1];

Then you just need to send authToken as the X-CSRF-Token header field. These usually don't change very often, so you can probably keep a copy around for a while.

MishieMoo
  • 6,620
  • 2
  • 25
  • 35
  • Very interesting! I like it because it's simple. I am also curious to what other solutions exist, but I am going to play with this in the meantime. – pacothelovetaco Jan 15 '13 at 16:49
  • I ended up going another route, though I liked your answer, and it is a solution, I am going to mark it as the answer. – pacothelovetaco Jan 18 '13 at 16:48
0

I ended up coming up with a token of my choosing. I setup the controller to check for the token using a before_filter. Then locking it all down with SSL.

before_filter :has_token?, only: :create
skip_before_filter :authenticate_user!, :verify_authenticity_token, only: :create

Here is the method I'm using to check for the token:

def has_token?
  if request.request_parameters[:token] == "SECRET"
    true
  else
    head :unauthorized
  end
end

Then the token is hard coded into the iPhone app and passed with the parameters that it sends to the Rails backend. I know this means that I have to release new versions of the iPhone app if that token has to change, but this way I have more control over what is going on.

pacothelovetaco
  • 2,361
  • 3
  • 16
  • 12