Using plain OAuth 2.0 for authentication would create a security hole big enough to drive a car through.

OAuth 2.0 implicit grant flow A good article by John Bradley [1] says that using RP for authentication opens a huge security hole big enough for a car to drive through. The comments are also worth reading. I checked it out and it seems to be completely wiped out. They need to fix the RP side, so it would be better to make a public announcement as soon as possible. I can't contact them one by one.
 
Check Facebook and all other sites that use OAuth login!

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 don’t want to read English, here’s a quick explanation:

If you try to "authenticate" using OAuth 2.0's implicit flow, it opens up a huge hole.

This is because cut and paste attacks are possible.

The flow of OAuth authentication is as shown in Figure 1.

Figure 1 OAuth authentication flow

At first glance, this doesn't seem like a problem. But that's only if all the sites are "good sites."

Let's say Site_A is actually a bad site, and Site_A manages to get hold of an access_token to impersonate this user.

From then on, Site_A can impersonate this user and log in to any site that uses OAuth authentication.

A non-technical introduction to the differences between OAuth authentication(?) and OpenID As I wrote in the article, I gave out a spare key with no address written on it, so I'm essentially saying that whoever has it is my alter-ego, so this is only natural.

To be more specific,

Site_A uses a browser (User Agent) UA to go to Site_B and try to log in. Site_B then tries to "authenticate" using the same procedure as above. UA receives an access token for Site_B, access_token_B, for the attacker, from the OAuth Authorization Endpoint (Authz), but does not pass this to Site_B. Instead, it passes the access token for the user (= victim) that it just obtained, access_token_A.Site_B has no way of knowing that the token is really meant for Site_A, so it accepts it as its own. AndSite_B then sends the access_token to GraphAPI in an attempt to obtain the victim's email and user_id.There is no way for GraphAPI to know that the token sent by this Site_A is actually from Site_B.Therefore, the GraphAPI will send back the victim’s email and user_id just as Site_A requested.As a result, Site_B will allow the attacker to log in as the victim [5].This flow is shown in Figure 2.

Figure 2 OAuth access_token substitution attack

This cannot be prevented even by using the OAuth state parameter to prevent 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 an OAuth issue.

OAuth is an Authorization Delegation Protocol, a protocol for delegating authorization, not a protocol for user authentication. [5] Frankly speaking, it is wrong to use it alone as a substitute for authentication just because it is convenient.

In fact, Facebook is aware of this too.signed_request They have an API called "http://www.openidconnect.org/." It's almost the same as OpenID Connect [2]. You have to use it to log in with Facebook. You do it with scope=signed_request . But how many people are using it? Are they doing it? Most of them are using it to get an access token. Client side flow (Facebook default) instead of authentication, right?! [7]

Eric Sachs, head of Identity Services at Google, also pointed out the importance of this in a post on John's blog:

A great article by John Bradley about how IdPs using plain OAuth for authentication instead of OpenID Connect are creating a huge security hole. This needs to be repeated everywhere - for IdPs to understand that they are creating security problems for their partners; for RPs to realize that they are undermining their own security by skimping on a few lines of code. A few years ago, when Google released their own API "AuthSub", which is now OAuth, they put a big note at the end of the documentation saying "Do not use this for authentication" for this exact reason. [3]

The cause of the problem is that the audience of an access_token is a resource endpoint, while the audience of a token used for authentication must be a client. Therefore, OpenID Connect issues an id_token with the client as the audience, which is separate from the access_token. The same goes for Facebook's signed_request.

Please fix it properly, everyone. Fixing it means making it compatible with OpenID Connect!

It's not a big deal, so please don't put your users at risk by adding a few lines [4][8].

 

[1] John Bradley. He is a member of the US government's ICAM, and is writing profiles for IMI, OpenID, and SAML. He is a director of the OpenID Foundation and chairman of the Kantara Initiative Leadership Council. This article is about his attempt to write a profile for OAuth authentication, and his conclusion that "this just doesn't work."

[2] While signed_request uses a signature method unique to Facebook, OpenID Connect uses JWS standardized by the IETF JOSE WG. Also, signed_request includes the access_token itself, but OpenID Connect leaves it out for 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] It would be fine if nothing would happen if the account was hacked, but if the account stores personal information of users, it would naturally result in a personal information leak.

[5] Bold part, added on 2/3.

[6] (Added 2/3) If an attacker, Site_A, passes on its own access_token to another person, the result is the same as if Site_A passed on the results of its own access. Therefore, from the perspective of the GraphAPI/Resource provider, Site_B using the access_token for Site_A does not pose any increased risk.

[7] (Added 2/17) If you use Facebook's Javascript SDK instead of writing your own code, you are now supposed to use signed_request. Furthermore, unlike the documentation, signed request has been changed since July of last year to include a code instead of an access_token. If most people use the JS SDK and don't write their own code, then the damage to Facebook is not that great. However, iOS SDK and Android SDK do not have such measures in place, so they are dangerous. @nov has filed an incident report with Apple about this.

[8] (Added 2/17) In the first place, it is impossible to pass the access_token passed to Javascript or other programs on the client device to the server side. Some have pointed out that if it is not passed, there should be no problem because the only information that the attacker can obtain is the information on the attacker's device, or the data on the platform side that the attacker was originally authorized to access. I hope this is the case, but for example, Facebook's developer materials (https://developers.facebook.com/docs/authentication/) have a diagram that shows the token being sent to the server.

2.0 thoughts on "Using plain OAuth 17 for authentication opens a security hole big enough to drive a car through"

  1. Figure 1 seems to be a normal flow of implicit flow, but in implicit flow, there is an oauth client in the browser, so if site-A represents the server side, the diagram of passing the access_token to site-A may be a little confusing with the code flow. In that sense, I also think that the way to write 'Your app' in the FB dev client-side flow is a little difficult to understand. Of course, there is no way to prevent the client (site-A's script) from sending the access_token to the server side.
    According to Figure 2, the token substitution attack seems to be performed on the UA side, but can a malicious script on Site-A capture the HTTP redirect response to Site-B? Is it assumed that there is no browser security?
    I'm asking because it's a topic I'm interested in. Sorry if it's completely off-topic.

    1. It might be confusing if you write "Site". In Figure 1, it doesn't matter if it's a code flow or an implicit flow, as long as Site A operated by the attacker can obtain the access_token. So, Site-A could be an iPhone app, an iframe app on apps.facebook.com, or an external site that is linked to Facebook like the NY Times. In Figure 2, it might be easier to think of UA as a jailbroken iPhone held by the attacker, and Site-B as Zy○ga's new iPhone game. There is no particular need for the script on Site-A here.

      1. Thank you. It might be possible to prevent this if the access token issued implicitly could be linked to the login session information (cookies, etc.) of the issuing destination and the AuthZ/Rsc server could check it based on that, but it probably won't work that well.

        1. As you pointed out, I think the OP manages access tokens by linking them to RP identifiers, and verification would be possible if the state parameters passed around by specifying session information were also linked and confirmed. However, access tokens are for resource access, and the current OAuth 2.0 access token specifications do not allow this. The ID Token proposed in OpenID Connect is defined as a token for obtaining authentication event information separately from access tokens, and is designed not to affect the OAuth 2.0 specifications. In addition, the specification includes a nonce parameter with a similar meaning to the state parameter, which can prevent replay attacks.

      2. I should have written RP instead of Site. Thinking about it now. I thought that some people might not understand RP, so I changed it to Client and then changed it to Site, which was a mistake.
        As I was writing the sequence, I left it as it was, thinking I'd fix it later.

  2. I learned a lot. But are there really that many sites that use Oauth for authentication? I think that using Oauth for authentication means that the site itself is entrusted to another service provider, but is this a common practice?

    I'm a little worried about whether I understand the problem correctly, so it would be helpful if you could give me an example of a site that uses Oauth for authentication.

    1. There are heaps of them. Sites that allow you to log in with Facebook use OAuth. For example, this comment system, disqus, does that. Leaving authentication for the site itself to another service provider is called authentication integration or federation. Technically, OpenID and SAML are also in this category. In most cases, normal sites cannot perform authentication properly (you wouldn't think of doing it with just a username and password, would you? Google and Facebook, for example, may look like password authentication, but in fact they are running risk-based authentication behind the scenes.), so it is better for the world and people to leave it to a place that does it properly.

      Let me ask the opposite question: what are your concerns about entrusting it to a third party?

  3. Just a question. "scope=signed_request" doesn't seem to be documented.
    https://developers.facebook.com/docs/authentication/permissions/

    > A signed_request parameter is used by Facebook to pass data to an application
    If this is the technology, I don't understand what it means in this context.
    https://developers.facebook.com/docs/authentication/signed_request/

    Also, in line with the theme of the article "Don't use client-side flow for authentication," I would like to ask a question.

    The SSO (Single Sign-On) feature of the Facebook iOS SDK is a very useful feature that allows smooth authorization through inter-app communication with the native Facebook app (if you're already logged in to the app, authorization can be completed with the click of a button). It is often used for authentication. Since it's called "Single Sign-On," I think Facebook also has it in mind for authentication purposes.
    https://developers.facebook.com/docs/mobile/ios/build/#implementsso

    However, this SSO function only implements the client-side flow. If you use this for authentication, copy-paste attacks like the one you mentioned will become possible, so I think it's a very poor design. What do you think?

Leave a comment

This site uses Akismet to reduce spam.For details of how to process comment data, please click here.