I've been implementing a Rails 4 application with an API. I want to be able to call the API from mobile phones and the webapp itself. I came across this note while researching protect_from_forgery
:
It's important to remember that XML or JSON requests are also affected and if you're building an API you'll need something like:
class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_action :verify_authenticity_token, if: :json_request?
protected
def json_request?
request.format.json?
end
end
I was thinking of doing this, but I have some reservations/questions:
- This solution seems to leave the CSRF hole open because now an attacker could craft a link with an
onclick
javascript that posts JSON? - Would checking for an API token be a reasonable substitute? i.e., what if instead of skipping the authenticity check, allowing it to fail the check and recover in
handle_unverified_request
if the api token is present and correct for current user? - Or maybe I should just make the webapp and mobile devices send the CSRF token in the HTTP headers? Is that safe? How would the mobile phone even obtain the CSRF token, given that it isn't rendering HTML forms to begin with?
Edit for clarification:
I am more concerned about the webapp user clicking a crafted CSRF link. The mobile users are authenticated, authorized, an have an API key, so I am not concerned about them. But by enabling CSRF protection for the webapp users, the mobile users are blocked from using the protected API. I want to know the correct strategy for handling this, and I don't believe the Rails documentation gives the right answer.