Reputation: 167
update (14/08/2015): Thanks to @EugZol's idea, I've updated the title, as the previous one is misleading.
I'm trying to build a Rails REST API server now.
I've read others' posts that I could use protect_from_forgery with: :null_session
to deal with the CSRF issue on JSON request, especially the POST request. I think this null_session will just clean the session(which is useless for JSON request).
But how could I do authentication on whether a user is logged in or not? I don't want to send password in every request. So I think maybe :null_session
is not safe.
I'll be really appreciated if you could provide me some idea about:
:null_session
specified?authenticate_token
, where should I put this token in my JSON response? And where should the client put it?Thanks a lot.
Upvotes: 2
Views: 327
Reputation: 6555
If you don't use cookies to authorize your client, CSRF can't be accomplished. It works only because browser would automatically add cookie to the request. E.g. when you open the following picture:
<img src="my.bank/withdraw_funds?to=john_doe">
you browser will make request to my.bank
with cookies attached, authorizing the transfer.
But if you use some API token (as a request parameter or as a header), there is no way to make a malicious image/form that will add that token to the request (because the attacker doesn't know a token).
And, yes, you should put this token into the database. Rails' session
use cookies, and API server, as mentioned, shouldn't rely on them.
You authentication method (probably somewhere in ApplicationController
) would look like this:
before_action :authenticate
def authenticate
@user = User.where(token: params.require(:token)).first
end
And then you can use @user
in your actions. On the client side you just add ?token=...
to your request parameters.
If you use headers (and it's better, at least because you shouldn't worry about token being saved in proxy servers' logs when you do GET requests), you add X-Authentication-Token: ...
header to your request, and then modify your ApplicationController
like that:
before_action :authenticate
def authenticate
@user = User.where(token: request.headers['HTTP_X_AUTHENTICATION_TOKEN']).first
end
Upvotes: 1