TL;DR OAuth2 sucks.
Please don't think about OAuth2 as about the next generation of OAuth1. They are completely different like colors: OAuth1 is the green version, OAuth2 is the red version
The biggest OAuth1 provider - Twitter.
I bet ($100!) they are not switching to OAuth2 in the near future. Pros and cons:
+ becoming compatible with the rest of social networks
- making authorization flow insecure, like the rest of social networks
I am not telling OAuth1 is super secure — it was vulnerable to session fixation a few years ago. If you made user to approve 'oauth_token' issued for your account, then you could use same oauth_token again and sign in his account on the Client website.
It was fixed in oauth1.a. Wait, read again: it was fixed. None of oauth2 vulnerabilities i pointed out in my previous posts a year ago was adressed in the spec. OAuth1 is straight, concise, explicit and secure protocol. OAuth2 is the road to hell.
Here we go!
OAuth2 core vulnerabilities - parameters
I have no idea why, who and, generally speaking, what the fuck, but we can transfer "response_type" as a parameter in URL (not as a setting of your Client).
Vector 1. Set respones_type=token in authorization URL and use specially crafted redirect_uri to leak access_token from URI fragment. You can add Chrome vulns like we did to hack Facebook. Hashbang #! is very nice bug too. Controlled piece of code (XSS) or mobile app like Nir did. BTW avoid pre-approved Clients ( Facebook Messenger with full permissions)
response_type must be a constant value in application settings.
Vector 2. If spec was implemented properly then tampering redirect_uri to other, "leaky", values is pointless. Because to obtain access token you must send redirect_uri value with client creds. If actual redirect_uri was "leaky" and not equal real redirect_uri Client will not be able to obtain access_token for this code.
Vk (vkontakte) was vulnerable to this attack until Sep 2012 - redirect_uri wasn't required to obtain token. An <img> on client website could leak victim's 'code' through referrer and attacker could use same 'code' to log in victim's account.
redirect_uri should be a constant value in application settings.
'scope' (actions User should allow for your Client) is also transfered in query string. I can't call it a major vulnerability, rather ugly user experience but anyway this is sort of stupid, no? "Pay as much as you wish, up to you"
Checking permissions after obtaining access_token is barely a right solution. This is rather a work around. Much better:
- if it's a parameter in URL then User should be able to remove some permissions by clicking [X]. This is my human rights, fuck yeah!
- if you really need some scope so badly - set it in Client's settings. Now you are 100% sure that User granted these permissions.
Authentication vs AuthorizationWiki
authorize = permit 3rd party Client to access your Resources (/me, /statuses/new)
authenticate = prove that "this guy" is "that guy" which has account on the website.
OAuth2 was designed for authorization purposes only, but now in 90% (yep!) of cases people authenticate with it too! They simply use /me endpoint and find a record in database by external_user_id and provider_name.
It leads to bad things happenning.
Vector 3: The Most Common OAuth2 Vulnerability or how I found CSRF based account hijacking vuln in most of OAuth2 implementations (omniauth, django etc)
Any implementation w/o 'state' is vulnerable to CSRF. It leads to session fixation (Alice is logged in as Mallory) and account hijacking (Mallory can log in as Alice because Alice connected Mallory Provider Account).
Vector 4: One access_token to rule them all or make sure access_token belongs to your Client
I truly love signed_request (Facebook feature!), it provides information about Client that issued this access_token. I think we should stop using response_type=token and use signed_request only. Because it is a reliable way for mobile and client side apps to obtain access_token+client_id of this token+current user_id (less round trips).
If we make redirect_uri constant and introduce encrypted_request (same data but encrypted with client_secret) it would be just perfectly secure flow.
XSS Threat, Vector 5
Nowdays XSS cannot steal user's session because of httpOnly flag (I assume everyone uses it).
Wait.. does OAuth2-based authentication have any protection from possible XSS on Client's website? No, attacker gets carte blanche:
- create iframe with response_type=token in authorize URL, then slice location.hash containing access_token
- use response_type=code and set wrong state. If CSRF protection is implemented 'code' will not be used and attacker can hijack User's account simply using this 'code' (within 10 minutes). Friendly reminder for Providers: 'code' must be used only once and within couple of minutes — I got $2000 bounty from facebook for finding replay attack.
- if csrf protection is NOT implemented (wtf?!) you can try a cool trick - 414 error. Set super long state (5000 symbols), facebook has no limits on state but Client server most likely has. 'code' won't be used because of server error - slice it!
- 'state' fixation + using callback with Attacker's code to hijack account
- always obtain access_token for every received code. But don't use it if state was wrong. "Destroy" code, or attacker will use it.
- clear state cookie as soon as it was used. "Destroy" state or attacker will use it.
Phishing Threat, Vector 6
Can you imagine how simple phishing is: create a Client with slightly different name: e.g. Skype -> Skype App/Skype IM, copy picture, description from original Client, use skype.com.evil.com domain.
- Verified Clients. Similar popup near Client name, like we have for twitter accounts.
- Add information about amount of Users this app has. I won't authorize "Skype IM" having only 12 users with such app installed.
Client Leaked All the Tokens.
What is Provider gonna do if some Client leaked all access_tokens at once (SQL injection for example). I think there should be kind of Antifraud system, monitoring token usage. And I am developing one btw, let me know if you wish to try.
I might be missing something, but why can't we use access_token + client creds to obtain a new access_token? refresh_token = access_token. If access_token is stolen it cannot be refreshed w/o client creds anyway. If client creds are stolen too = Game Over.
Dear Providers, please, add valid_thru parameter, I want to set for how long the Client has access to my Resources.
Last but not least threat, MITM
SSL and encryption. OAuth2 relies heavily on https. This makes framework simpler but way less secure.
so, OAuth...?This is a sad story. And I don't know what to do and how to fix it.
Who to join? OAuth2.a? i am just a russian scriptkiddie nobody listens to :/
Framework, not protocol, they said.
coming a mess big frameworks authorization in