Wednesday, August 29, 2012

How To Cheat On Facebook Apps Permissions

Facebook doesn't care about your privacy, but you should. Facebook implements OAuth2 - readers of my blog know how shitty OAuth2 is and how awesome OAuth2.a will be.

Apps actually cannot require permissions ('scope' param). They propose it, but you can choose them - update authorization URL.

Example - you are redirected to:

Just change 'scope' param

And authorize the app. You permitted nothing special but app works - enjoy.

The post  had nothing to do with security. I was annoyed with terrible fact "you can ask permissions, it will look legit and user cannot uncheck them in UI. Well if he's smart enough to change URL - you have to check permissions in your code" 

There are two ways to fix it (OAuth2.a deals with the issue this way):
1) when app has "frozen" scope. This is not param in URL anymore, just a field in the database. Developer doesn't need to make sure what is allowed anymore - he is sure.
2) when app has "agile" scope. Client 'proposes' scope and User can uncheck not desired permissions. App should check explicitly what was permitted.

Tuesday, August 28, 2012

OAuth2: One access_token To Rule Them All

One access_token to rule them all...
I demonstrated The Most Common OAuth2 Vulnerability in Authorization Code Flow a while ago – signing in the Victim's account(followed by getting an access to Victim's resources on that website) by connecting Attacker's oauth account through CSRF-callback URL with Attacker's code. Despite popularity of that attack, it can be easily mitigated with 'state' param(to prevent CSRF) – and now it's fixed in popular ruby/python libraries.

Now I want to share a very straightforward attack for Implicit Flow based websites(realized in brainstorming with @isciurus). There is no proper mitigation so far.

Generally speaking:
  1. 'access_token' is a string that identifies your Resources on Provider. No other parameters are required to call Provider's API. There is no guarantee user's access_token1 for client1 is not used by client2 or client75 - nothing stops them.
  2. Let's assume I create a website: e.g. I ask my users to authorize my Client on facebook and I don't ask any scopes at all - I need only "/me" endpoint with "uid" param to be available. They authorize my Client because requires only 'read' access and nothing seems to be dangerous. I get their 'access_token's and now I can request /me endpoint and get their "uid"(often used for authentication)
  3. Let's assume there is another site: e.g. and yep, it uses Implicit Flow(receives token via CALLBACK#access_token=123qwe...). It's a pity - this website authenticates users by given access_token. Most likely it sends access_token on server-side and invokes /me endpoint from there.
  4. Since I am admin of and you authorized my Client and gave me an access_token from your account I just put that access token in callback URL: CALLBACK#access_token=YOUR_TOKEN and now's Client authenticates me as you because that token I just provided returns your 'uid' when /me endpoint is called. I need only one access_token from your Provider's account to rule all your accounts on 3rd party websites that use Implicit Flow.
OAuth2 is extremely insecure for authentication goals by default. 
  • Auth Code Flow: You must use 'state' parameter and verify - is this user the same user you sent to authorization URL by checking state value from session and returned one.
  • Implicit Flow: You must ensure that access_token you are going to use is issued for your Client. Please, use this URL for Facebook: Not all providers support this feature though. If access_token is anyhow obtained from User (not from Provider) - you must verify is this access_token issued for your Client.
Oh, also:
As I mentioned in my previous post on stupidity of OAuth2 - if Provider has Implicit Flow as an option - lots of Users can be compromised someday. If a single XSS is found on Client's domain - hackers can steal all access_tokens with it even if your website uses Auth Code Flow by just changing response_type param in authorize URL. 

OAuth2.a - simple and secure. Join! Honestly, yeah, OAuth2 is Road To Hell. Deal with it. But OAuth2.a is road to Simple and Secure both Authentication and Authorization. I am implementing Provider - charm. If you trust me and have a popular RoR website that needs OAuth - ping me, I will help you to introduce OAuth2.a and make your API users happier.
Author of this article is awesome - you can actually hire him.

Wednesday, August 1, 2012

SaferWeb: OAuth2.a or Let's Just Fix It

Eran and others, chill out. We should stop whining to nobody. I prefer rather "we gotta fix this, this and discuss that" than "it is bad"-attitude. Some people were surprised because they like OAuth2.

What about me? I was not surprised because OAuth2 is far from perfect. But there is no reason to give up, it's in our hands. ( By the way I'm waiting for comments on Hacker News OK?)

Below I explain some security and usability concerns about current OAuth2 and propose(I do, not just say 'it is bad') improvements to make it more agile and safe-by-default. OAuth2.a is going to be easier to implement and more secure.


  1. redirect_uri can be on any domain and amount of redirect_uri-s is unlimited. They are whitelisted and only exact match verification is applied(redirect_uri IS NOT flexible*). Client sets redirect_uri-s on his admin page in Provider.
  2. for every redirect_uri MUST be defined certain response_type - token or code. It must not be possible to set response_type in authorize URL. Every redirect_uri has its own defined response_type
  3. Most Common OAuth2 CSRF Vulnerability from my previous post. We should either introduce a new *compulsory* param(e.g. csrf_token) or just raise awareness about the issue.
  4. We need either assign 'scope' to certain redirect_uri as well as response_type(it MUST not be in URL) or allow user to choose what parts of scope to allow. It's up to Provider's implementation.
  5. We should introduce 'mass refreshing' of access_token-s. Client sends an array of refresh_token-s and client's credentials and get's hash with refresh_token=>access token.
  6. We need to define some DEFAULT URL paths and error codes to add a little bit more "interoperability". Really, is it so damn hard to keep your endpoints and error codes similar to other services?