Is it safe to use a signal auth-token in cookie for auth (post and requst only json via ajax)?
Why attacker can not get the form token in hidden field?
How an attacker do a CSRF attack with a POST request?
Is it safe to use a single token in a cookie for authentication?
Sort of, if that cookie is HTTP-only (which helps protect against XSS) and SSL then there's no way anyone outside your site can read that cookie.
However, the user's browser can retain that cookie, and will automatically send it whenever their browser requests a page from your application again. This is desired when the user is navigating your site, but also how a CSRF attack is possible.
Why can't the attacker get the form token in a hidden field?
In a CSRF attack the hacker can't actually read your site or the cookie because it should be protected by SSL/HTTPS. CSRF works by fooling your browser into sending their data along with your secure data to your site.
So a value in a hidden field is part of the default defence against CSRF - they have a secret value in a cookie (which the hacker can fool the browser into re-sending but can't see or edit) and the same value in a hidden input field in the encrypted page (which the hacker can't get to). If the cookie and the hidden value don't match then you have a CSRF attack.
How does an attacker carry out a CSRF attack with a POST request?
Ok, so suppose you have a secure website. You can log into this site using SSL and you'll get an HTTP-only SSL authentication cookie back that keeps you logged in.
Now I have a new page, on a completely different site. If I link to your site from mine then when you click on that link it will leave my site and go to yours, passing your cookie.
If I add an HTML <form> to my page that POSTs back to your site the same thing happens: the browser goes back to your site and sends any data in the form, along with your cookie.
Note that I haven't read either your cookie or any pages on your site, as both are protected by SSL encryption.
For the full effect I can hide that form on the page so that the user doesn't even realise that they're posting back to your site.
A trivial example of this is the 'Like' functionality on Facebook - they've patched this now I think, but for a while I could fool your browser (without accessing your details) into sending your authentication cookie to the Facebook action that says you like something I want you to.
Related
I'm implementing a per-page CSRF token in a web app. However, I had a thought. What happens if, before an attacker submits a malicious POST request, they submit a GET request on the page and capture the CSRF token? Is there anything in place that I can protect against an external site requesting data from my web app?
Nevermind, I figured out my own question. If you store the CSRF token in a client cookie then the cross-origin policy prevents it being read.
Looking at Google OpenId connect and Facebook login I noticed that Facebook always hits the "redirect URI" from the browser. To explain a bit more - when user follows link of the form
https://www.facebook.com/dialog/oauth?client_id={app-id}&redirect_uri={redirect-uri}
S/he is always redirected to the URL specified by {redirect-uri}. This URL then contains "code" which can be exchanged for access token.
Google has similar approach but when using "server-flow" the {redirect-uri} is "hit" by Google's servers. This way the code which needs to be exchanged for access token never gets shown to the user.
It seems like FB's approach is less secure as the access code can actually end up in the attacker's hands.
Is there a way to have FB send the code to a redirect URI but not actually redirect client? Something like what Google does.
Does anyone have a good explanation why FB does not have "server-flow"-like behaviour but only "implicit-flow"?
You should grab the code from the server then use it, together with your app secret, to exchange an access token on Facebook. It does not matter if the client can see this because without the app secret, that code is useless. And the app secret is kept on your server, it is never revealed to the client.
Facebook's server-side login process mentions that the server should provide a 'state' variable during the request to Facebook. It acts like a CSRF token in which Facebook will pass back to login-callback page for our server to verify.
However I am not sure why this is necessary. If we do get a bogus login request, we still need to get the access_token from Facebook using the ?code= of the login request. A bogus request will not have the correct code, therefore won't work correctly.
Furthermore, a user can access our server through Facebook App's link. Facebook automatically adds a ?code= param to the link so our server can/have-to auto login the user. If we are to use code provided by this referral, we have no state param to verify anyways, and Facebook seems to not care about it either.
Is state optional? Does it really provide extra security?
The state parameter is optional. It may provide extra security if your service can put some information there worth keeping. Usually the state parameter is used for keeping data about the state of the session for the current browser window (as opposed to data dealing whole session which can be handled with cookies).
An example of using this feature for extra security would be doing following:
User visits your site
Your site sets session cookie (e.g. Set-Cookie: id=xyzrandomstuff)
User tries to do something that requires doing facebook authentication
Your site creates CSRF token that can be used with session id xyzrandonstuff and puts that in the state parameter for the facebook login
User completes login at facebook (you cannot see this)
User comes back from facebook with code and state parameters.
You verify login with code and before completing the action started at step 3 your server verifies that the CSRF token matches the current session.
So I'm building my app around facebook oauth, and was hoping to use the fbsr_ token to identify logged-in users (so that the facebook-js stuff stays in sync with my site).
Unfortunately, it appears that these fbsr_* cookies are set to expire within a day. Which means if the user comes to my site a day later, they have no cookie and are shown a logged-out experience.
The facebook-js then runs, recognizes them, creates the fbsr_* cookie, and gives me a callback. I can choose to do a hard page refresh (rather jarring), or try to do fancy in-place ajax updating (tons of complex code, still slightly jarring). Is there a reason these cookies don't have a longer expiration so the user stays logged-in seamlessly? Most websites allow you to "remember me" when you log in to avoid constant cookie expirations, so I'd rather not have my facebook-enabled website keep logging me out.
Is there anything I can do about this? I suspect I can probably switch to serverside-oauth where I manage identity and cookie expiration myself (yes?). But it seems strange that clientside-oauth would have such a limitation, so I'm hoping I'm missing something.
Is there anything I can do about this?
No, not really.
The only way to determine, if a user is currently logged in to Facebook, is to look at the cookie set for the domain facebook.com.
The JS SDK is capable of doing that, because it runs client-side, and can make a cross-domain request to check if these cookies are set.
But there is no way to check for those cookies server-side from your domain – your server only has access to cookies set for your own domain.
I suspect I can probably switch to serverside-oauth where I manage identity and cookie expiration myself (yes?)
If your set your own cookies on your domain, you are implementing your own login system.
And even if you “fake” the cookies that the JS SDK sets under your domain, it would not bring the same results.
There might be a cookie on your domain, that says, “yes, user XYZ is logged in to Facebook” – but that would not have to be the case. I could have logged out of Facebook in the meantime, and your cookies would not reflect that at all. So whatever you’ll try to do next, like f.e. posting something on my behalf from your app, will most likely fail, because you only think I was still logged in to Facebook, but in reality you do not have a valid access token for me any more, since I am not really logged into Facebook.
The facebook-js then runs, recognizes them, creates the fbsr_* cookie, and gives me a callback. I can choose to do a hard page refresh (rather jarring), or try to do fancy in-place ajax updating (tons of complex code, still slightly jarring).
Those are your only viable options.
With the new Authenticated Referrals in the new FB auth system, the user logs in before even hitting my app.
My question is, is there any way to detect when a user has just come from one of these authenticated referrel dialogs? For example, by specifying the redirect_uri on them and appending some GET params.
If you go to https://developers.facebook.com/apps/YOUR_APP_ID/summary you can set the domain and the website of your application.
Facebook, for security reason will only redirect to the website you set here passing you some parameters in the HTTP GET url (for example the access token just generated for that user), to decide which of these parameter you want to receive you have to go to settings -> auth dialog then at the bottom of the page Authenticated Referrals -> Auth Token Parameter.
EDIT:
If you want to be sure that an user just used the auth dialog you can use a simple workaround: read the access token from the url, then check if this is the 1st time you see this token, if so you can test the validity of the token by performing a simple operation that the particular user accepted you (or better your facebook app) can do with his profile.. The easiest way is probably to send a request to:
https://graph.facebook.com/me?access_token=...
If token is valid then it IS reliable.
I've been working on this problem myself. It would have been a lot better if Facebook just passed auth_ref=true or something. Anyway, I came up with a system that seems to work for me using cookies.
I already have a page that I use as the redirect url for the fb auth dilaog. This page initializes the user and sets a cookie. If that cookie is not present and the signed request has a token, then I redirect to this page. I can't tell if the user either came from an authenticated referral or some other path like a bookmark, but it doesn't matter for my purposes.
You can see the details at:
http://developsocialapps.com/authenticated-referrals-facebook-apps/
Basically something like this:
// on somepage.php
if (signed request has token && url is not redirect page && user doesn't have cookie) {
redirect to redirect.php;
}
// on redirect.php
set cookie;
redirect back to somepage.php