

In some of the feedback I have gotten on the openID Connect spec, the statement is made that Connect is too complicated. That OAuth 2.0 is all you need to do authentication. Many point to Identity Pro…
For those who do not want to read the English, here is a brief explanation…
If you try to use the OAuth 2.0 implicit flow for “authentication,” you create a very large hole.
That is because a cut-and-paste attack is possible.
“OAuth authentication” follows the flow shown in Figure 1.
At first glance, it seems that there is no problem. But that is true only if every site is a “good site.”
Now suppose Site_A is actually a malicious site. Site_A has then managed to obtain an access_token that lets it impersonate this user.
From that point on, Site_A can impersonate the user and log in to any site that uses “OAuth authentication.”
As I also wrote in An Introduction for Nontechnical Readers to the Difference Between OAuth Authentication (?) and OpenID, this is only natural: you are handing over a spare key with no destination written on it and declaring that anyone who holds it is your alter ego.
More concretely:
Site_A uses the browser (User Agent), or UA, to visit Site_B and try to log in. Site_B then attempts “authentication” using the same procedure described above. The UA receives from the OAuth Authorization Endpoint (Authz) an attacker access token for Site_B, access_token_B, but instead of giving it to Site_B, it supplies the user’s (that is, the victim’s) access token obtained earlier, access_token_A.Site_B has no way to recognize that this token was actually issued for Site_A, so it accepts the token as one intended for itself. Site_B then sends the access_token to the GraphAPI and attempts to obtain the victim’s email and user_id.The GraphAPI likewise has no way to recognize that Site_B is the party sending this token for Site_A. Consequently, the GraphAPI returns the victim’s email and user_id just as it would if Site_A had made the request. As a result, Site_B logs the attacker in as the victim[5]. This flow is shown in Figure 2.
This cannot be prevented even if the OAuth state parameter is used as protection against XSRF. In other words, an OAuth 2.0 Client can impersonate anyone who has logged in to that Client (site) and log in to any other OAuth-enabled site.
This is not a problem with OAuth.
OAuth is an Authorization Delegation Protocol—a protocol for delegating authorization—not a protocol for user authentication[5]. Frankly, the fault lies with those who use it by itself as a substitute for authentication simply because it is convenient.
Facebook is in fact aware of this and has an API called signed_request. It is almost the same as OpenID Connect[2]. You have to use this to log in with Facebook. You do it with scope=signed_request. But how many people actually use it? Do you? Most people use the client side flow for obtaining an access token (the Facebook default) as a substitute for authentication, do they not?![7]
A comment on John’s blog by Eric Sachs, who heads Google’s Identity Service, also points out the importance of this issue.
A great post by John Bradley about the enormous security hole created by IdPs that use plain OAuth, rather than OpenID Connect, for authentication. We need to keep repeating this point everywhere: so that IdPs understand that they are creating security problems for their partners, and so that RPs realize they are ruining their own security just to save a few lines of code. Years ago, when Google released AuthSub, its proprietary API corresponding to today’s OAuth, its documentation prominently warned at the bottom, for exactly this reason, that it must not be used for authentication.[3]
The cause of the problem is that the audience of an access_token is the resource endpoint, whereas the audience of a token used for authentication must be the client. That is why OpenID Connect issues an id_token whose audience is the client, separately from the access_token. Facebook’s signed_request works the same way.
Please fix this properly, everyone. Fixing it means supporting OpenID Connect!
It does not take much work. Please do not put users at risk[4][8] just to save a few lines of code.
[1] John Bradley works on ICAM for the U.S. government and writes profiles for IMI, OpenID, and SAML. He is a director of the OpenID Foundation and chair of the Kantara Initiative Leadership Council. Apparently, this article came about when he tried to write a profile for OAuth authentication and concluded, “This just won’t work.”
[2] signed_request uses Facebook’s proprietary signature scheme, while OpenID Connect uses JWS, which is standardized by the IETF JOSE WG. Also, signed_request includes the access_token itself inside the signed_request, whereas OpenID Connect keeps it separate in consideration of compatibility with other OAuth 2.0 sites.
[3] Original: Great post by John Bradley on the huge security hole many IDPs have created by using plain OAuth, instead of OpenIDConnect, for authentication. We need to keep hammering away on this point both so IDPs realize the security problems they are creating for their partners, and to get RPs to realize how easily they can compromise their own security just because of the lack of a few additional lines of code. Years ago when Google first launched its proprietary equivalent of OAuth, called AuthSub, we had a big section at the bottom warning people not to use it for authentication for exactly this reason. (source: https://plus.google.com/u/0/102425765611793764729/posts/UKcZQzuvosQ )
[4] If nothing would happen even if the account were hijacked, that would be fine. But if the site stores users’ personal information, this would of course become a personal-data breach.
[5] Bold text added on 2/3.
[6] (Added 2/3) When the attacker Site_A gives an access_token intended for itself to someone else, the result obtained is the same as if Site_A had accessed the resource itself and passed along the result. Therefore, from the perspective of the GraphAPI/Resource provider, Site_B’s use of an access_token issued for Site_A does not create any additional risk.
[7] (Added 2/17) If you use Facebook’s Javascript SDK rather than writing the code yourself, it is designed to use signed_request. Furthermore, since 7 last year, contrary to the documentation, signed request has contained a code rather than an access_token. If many people use the JS SDK instead of writing their own code, the damage involving FB may not be that severe. However, the iOS SDK and Android SDK do not have this safeguard, so they are dangerous. @nov has submitted an incident report about this to apple.
[8] (Added 2/17) Some have also pointed out that an access_token handed to something on a client device, such as Javascript, should never be sent to the server side in the first place. If it is not sent, there should be no problem, because at most it could retrieve information stored on the attacker’s device or data on the platform that the attacker was already authorized to access. I hope that is indeed the case, but Facebook’s developer documentation, for example (https://developers.facebook.com/docs/authentication/) and similar pages), includes a diagram showing it being sent to the server.


You must be logged in to post a comment.