CSRF protection - what happens if an attacker performs a GET request before the POST? - csrf

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.

Related

OAuth2 : redirect_uri post LinkedIn & Facebook

I'm performing the server side oAuth2 flow.
I noticed that google has added a cool feature for their oAuth2 signin API which is redirect_uri=postmessage so we don't show the real redirect_uri on the browser url bar and the authorization code won't be included in the redirect url.
For linkedin, when the users accepts to share his personal data with the app, the response url looks like :
http://dev.localhost.com:8080/auth/linkedin?code=xxxxxxxxxxx&state=yyyyyyyyyyyyy
it's the same for Google unless we replace the real redirect_uri by postmessage.
If the redirect_uri + the response code is set in the url Every malicious script could be able to retrieve the returned code from the url and perform its own authentications.
So, is there any way to hide the return parameters and the redirect_uri for LinkedIn and Facebook ?
LinkedIn and Facebook are not vulnerable to malicious scripts accessing the redirect_uri.
Assuming you use the recommended response_type=code both APIs require you make a request from your server that includes your API secret and the code value in order to get the users token. LinkedIn describes this in Exchange Authorization Code for a Request Token and Facebook describes this in Exchanging code for an access token.
Additional security with Facebook can enabled with requiring that every request be signed with your API secret. Additional protection in general can be had by using a strong Content Security Policy to help prevent malicious scripts from running in the first place. And be sure to host your site exclusively over TLS to prevent your own JavaScript from being modified.

REST API for website which uses Facebook for authentication

We have a website where the only way to login and authenticate yourself with the site is with Facebook (this was not my choice). The first time you login with Facebook, an account gets automatically created for you.
We now want to create an iPhone application for our site and also a public API for others to use our service.
This question is about how to authenticate with our website from the app/API and is broken into 2 parts:
What is the correct way to handle REST authentication from an API to a website which only uses Facebook OAuth as an authentication method?
I have read and researched a lot about standard methods of authentication for REST API. We can't use such methods as Basic Auth over HTTPS, as there are no credentials for a user as such. Something like this seems to be only for authenticating applications using the API.
Currently, the best way I can think is you hit an /authorize end-point on our API, it redirects to Facebook OAuth, then redirects back to the site and provides a 'token' which the user of the API can use to authenticate subsequent requests.
For an official application that we create, we wouldn't necessarily need to use the public API in the same way. What would be the best way then to talk to our website and authenticate users?
I understand (I think) how to authenticate 3rd-party applications that are using our API, using API (public) keys and secret (private) keys. However, when it comes to authenticating the user who is using the app, I am getting rather confused about how to go about it when the only way we have to authenticate a user is Facebook.
I feel like I'm missing something very obvious, or don't fully understand how public REST APIs should work, so any advice and help would be greatly appreciated.
UPDATE: see below
I've been thinking hard about this question too. It's not entirely clear to me yet but here's the route I am thinking of going. I am creating a REST API an my users only auth with Facebook connect.
On the CLIENT:
Use the Facebook API to login and get an OAUTH2 code.
Exchange this code for an access token.
In every call to my custom API I'll include the Facebook user id and the access token.
On the API (for every method that requires user authentication):
Make a request to the /me Facebook graph using the access token from above.
Verify that the Facebook user id returned matches the user id passed to my API from above.
If the access token has expired additional communication is required.
I have yet to test this. How does it sound?
--- Update: July 27th, 2014 to answer question ---
I only use the above exchange once upon login. Once I determine which user is logging in, I create my own access token, and that token is used from that point going forward. So the new flow looks like this...
On the CLIENT:
Use the Facebook API to login and get an OAUTH2 code.
Exchange this code for an access token.
Request an access token from my API, including the Facebook token as a parameter
On the API
Receive access token request.
Make a request to the /me Facebook graph using the facebook access token
Verify that the Facebook user exists and match to a user in my database
Create my own access token, save it and return it to the client to be used from this point forward
This is my implementation using JWTs (JSON Web Tokens), basically similar to Chris' updated answer. I have used Facebook JS SDK and JWT.
Here's my implementation.
Client: Use Facebook JS SDK to log in and get the access token.
Client: Request JWT from my API by calling /verify-access-token endpoint.
MyAPI: Receives access token, verify it by calling /me endpoint of Facebook API.
MyAPI: If access token is valid, finds the user from database, logs in the user if exist. Create a JWT with required fields as payload, set an expiry, sign with the secret key and send back to the client.
Client: Stores the JWT in local storage.
Client: Sends the token (the JWT from step 5) along with the request for the next API call.
MyAPI: validate the token with the secret key, if token is valid, exchange the token for a new one, send it back to the client along with the API response. (No external API calls for verification of the token here after) [if the token is invalid/expired request client to authenticate again and repeat from 1]
Client Replaces the stored token with the new one and use it for the next API call. Once the token expiry is met, the token expires revoking access to API.
Every token is used once.
Read more answers about security and JWT
How secure is JWT
If you can decode JWT how are they secure?
JSON Web Tokens (JWT) as user identification and authentication tokens
I am trying to answer the same question and have been going through a lot of reading recently...
I won't have "the" answer but things are getting a little clearer for me. Have you read the comments in the article you mentioned? I found them really interesting and helpful.
As a result, and in the light of how things have evolved since the first article has been written, here's what I think I'll do:
HTTPS everywhere — this allows you to forget about HMAC, signing, nonce, ...
Use OAuth2:
When authentication requests come from my own apps/website, use this 'trick' (or a variation of it) described in a reply to the article mentioned before.
In my case, I have two types of users: those with classic login/password credentials and those who have signed up with Facebook Connect.
So I'd provide a regular login form with a "Login with Facebook" button. If the user logs in with his "classic" credentials, I'd just send these to my OAuth2 endpoint with a grant_type=password.
If he chooses to log in via Facebook, I think that would be a two-steps process:
First, use Facebook iOS SDK to open an FBSession
When that's done and the app is given back control, there should be a way to get a Facebook ID for that user. I'd send this ID alone to my OAuth2 endpoint with an extension grant understood by my server as "using an FB User ID".
Please note that I am still heavily researching on all this stuff, so that might not be a perfect answer... maybe not even a correct one! But I think that would make for a good starting point.
The idea of using an "extension grant" for the Facebook authentication might involve having to register it to do things properly? I'm not quite sure.
Anyway, I hope I was able to help you even a bit, and that at least it can start a discussion to find the best solution to this problem :)
Update
The Facebook login is not a solution as pointed in the comments: anybody could send an arbitrary user ID and log in as this user on the API.
What about doing it like this:
Show a login form with a "Facebook login" button
If this login method is chosen, act kinda like the Facebook SDK: open a web page from your authentication server, which will initiate the Facebook login.
Once the user has logged in, Facebook will use your redirect URL to confirm; make that URL point to another endpoint of your authentication server (possibly with an extra parameter indicating the call came from an app?)
When the authentication endpoint is hit, the authentication can securely identify the user, retain its FB User ID/FB Session and return an access token to your app using a custom URL scheme, just like the Facebook SDK would do
Looks better?

Questions about CSRF

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.

Facebook access token: server-side vs client-side flows

Facebook docs:
Facebook Platform supports two different OAuth 2.0 flows for user login: server-side (known as the authentication code flow in the specification) and client-side (known as the implicit flow). The server-side flow is used whenever you need to call the Graph API from your web server. The client-side flow is used when you need to make calls to the Graph API from a client, such as JavaScript running in a Web browser or from a native mobile or desktop app.
What is the difference between access tokens taken by these flows?
It seems like they length differ.
Can we use server-side flow token on a client? And otherwise, can we use client-side flow token on a server?
Currently, Facebook says this about access_tokens. On Server-side OAuth
if the access_token is generated from a server-side OAuth call, the
resulting access_token will have the longer expiration time by
default. If the call is made while there is still a valid long-lived
user access_token for that user, the returned user access_token from
this second call may be the same or may have changed, but in either
case the expiration time will be set to a long expiration time.
Where as client-side OAuth flow will give you a existing, non-expired, short-lived user access_token. To make this access_token long lived, facebook is providing a new endpoint that exchanges the short lived access_token with an access_token with longer life. The endpoint is
https://graph.facebook.com/oauth/access_token?
client_id=APP_ID&
client_secret=APP_SECRET&
grant_type=fb_exchange_token&
fb_exchange_token=EXISTING_ACCESS_TOKEN
Also please note that
Currently the long-lived user access_token will be valid for 60 days
while the short-lived user access_tokens are currently valid from 1 to
2 hours.
Excerpt from https://developers.facebook.com/docs/roadmap/completed-changes/offline-access-removal/
For those that like me are facing the same issue in 2014, Facebook improved the documentation on access tokens.
Tokens are Portable
One important aspect to understand about access token is that they are portable. Once you have an access token you can use it to make calls from a mobile client, a web browser, or from your server to Facebook's servers. If a token is obtained on a client, you can ship that token back to your server and use it in server-to-server calls. If a token is obtained via a server call, you can also ship that token down to a client and then make the calls from the client.
(from https://developers.facebook.com/docs/facebook-login/access-tokens/#portabletokens)
So yes, you can use access tokens from the client on the server and vice-versa; as already stated by naveen, the difference is that client-obtained tokes are short lived, whilst server ones are long lived. You can also convert a short-lived token to a long-lived token by following the directions here: https://developers.facebook.com/docs/facebook-login/access-tokens/#extending
Token can be used to make API calls since it represented that you are authenticated and authorized to do something.
Code can not be used directly to make any API call. It must be first redeemed with your app secret to get a token.
In other words, code is like an encrypted token that only parties with app secret can decrypt it.
BTW, your app secret should only appears in your server code, never in mobile or web client.
The video basically explains all this at around 13:00
https://developers.facebook.com/docs/facebook-login/security
A user access token (and page access token) will be the same in either server-side or client-side environment (other than maybe for the time stamp expiration).
An app access token will be exactly the same either server-side or client-side.

Facebook authentication and Ajax

I am building a Facebook application, and using the oAuth 2.0 protocol for authentication/authorization.
When a user first visits my app I am using the protocol and store the access token in order to make future requests to the Graph API. The problem occurs when the access token expires and the user is using ajax.
When the ajax request is sent I try to retrieve information from the Graph API using the access token, but since it expired I get a JSON saying the access token is invalid. Now, I can send a response back to the client saying the access token expired and on the client side I can redirect him to https://www.facebook.com/dialog/oauth to go through the authentication process again. However, since the whole process is in Ajax, redirecting the user will hurt the usability of the application.
Is there any other way I can use the protocol to get a new access token without needing to redirect the user's browser to get a new access token? Maybe something on the server side?
You just need to ask for the offline_access permission, then your access_token will not expire.
As Rafael notes, you can ask the user for offline_access and then the token should never expire. However, in practice, the access token does expire when a user changes their password or uninstalls/reinstalls your app, so you'll need to build a way for the user to reauthenticate themselves so you can update their token. I suggest redirecting them to a login page that should (ideally) just send them right back where you tell them to go without them having to do anything, and using deep linking to put them right back in your app where they left off.
I'm encountering this issue as well. One solution I came up with is as follows:
Create an async method called isAccessTokenValid()
Invoke isAccessTokenValid() before any method that will require FB interaction
If access_token has expired. save the current uri to the session, along with any form data entries (if any), and start the re-authentication process again.
Once the user has re-authenticated, bring up the stored uri.
This is a bit dirty, but I haven't seen a cleaner solution yet.