5 ms·
In the proof of concept[1]: 1. Send an ajax HEAD request, which grants the permissions. 2. However, since the HEAD response doesn't have valid CORS headers, y
by diafygi 7y ago
In the proof of concept[1]:
1. Send an ajax HEAD request, which grants the permissions.
2. However, since the HEAD response doesn't have valid CORS headers, you can't read the 'code' parameter from the HEAD response.
3. To get around CORS, the proof-of-concept redirects the user to the same OAuth url again.
4. Since the user has already authorized the scope (from the previous HEAD request), Github automatically redirects back to the redirect_uri (the proof-of-concept page) with a new 'code' that the author can then use.
So I have two questions:
a) If I have 3rd party cookies disabled, will the "credentials: 'include'," part of the ajax HEAD request still work?
b) Why does Github automatically redirect back the 2nd time without asking the user to authorize again? I thought it was best practice to ask the user to click authorize every time even if they're authorizing the same scope they previously authorized?
[1]: https://not-an-aardvark.github.io/oauth-bypass-poc-fbdf56605489c74b2951/ https://not-an-aardvark.github.io/oauth-bypass-poc-fbdf56605...
- homakov 7y agoOnly step 1 is important, that's where the bug is. The rest is routine to get a code for your already authorized app.
- zaroth 7y agoWhy would you want to ask the user to authorize an app they already authorized? IMO that would be a bug and definitely unexpected behavior. It would give the end-user the impression the app was not authorized when in fact it was, which could create its own issues. So now you’re designing a whole different page which shows the app is authorized with a POST form just to do the redirect? And if the entire purpose is to try to avoid any place that you can GET a redirect to the app, you better hope that’s the only place where it could happen.
- diafygi 7y agoHmmm, as a user, I guess I would expect the opposite behavior, and I'd think the question should be why wouldn't you want to ask the user to authorize and app they already authorized? A client should usually only redirect the user to the OAuth authorization endpoint when: (a) they don't have an access_token (e.g. they haven't asked for authorization yet) (b) their current access_token or refresh_token got rejected (e.g. the resource owner revoked access, so they need to reauthorize) (c) they want to change scope of access So the situation where you redirect the user to the OAuth authorization endpoint when they've already granted access and with the same scope is usually when something strange is going on (like when the client loses your access_token or this exploit happens). So why would you have different behavior (not asking to click Authorize) just to streamline the atypical scenario? Especially when it leaves open the possibility to be exploited[1], create confusing situations[2], or be mis-categorized as an opt-in event when it isn't[3]. As a user, I'd like to think that I'd always get the same behavior every time I'm redirected to an OAuth authorization endpoint, because the OAuth provider doesn't have any idea what the situation is on the client side and assuming it's okay to auto-redirect without asking for my consent again is dangerous. [1]: This HEAD bug would have not been able to be exploited in the wild if the auto-redirect wasn't in place. [2]: In clients that allow users to have multiple accounts (where each can hook-up a github connection), auto-redirects creates confusing revocations across the multiple client accounts. For example, Bob authorizes a github connection to account A, then when he switches to account B wants to authorize github again. If auto-redirect is in place, then Bob wouldn't see anything (since it is a transparent redirect), but account B's connection would start working and account A's connection would silently stop working. If there were an authorize click, Bob would see the same behavior for account A and account B, and probably be able to put together that if he clicks authorize on one account, the other stops working. Auto-redirects makes Bob figuring out what's going on really hard. [3]: Privacy regulations are requiring opt-in more and more, and OAuth is seen as a fairly good mechanism for proving someone "opt'd in". If a regulation requires a "consent" to have an expiration (e.g. an accounting app must require the user to re-authorize bank access on a yearly basis), then when the users is asked to "consent" again, if they get auto-redirected, they can later claim they were never asked to consent because they never clicked authorize again after a year.
- zaroth 7y agoYou raise good points. I just wonder -- and I don't know enough about OAuth to say -- is there really no other way for the attacker to discover their token, since Github was still in a state where they though the attacker had been authorized? I think you should post this on Github's HackerOne, maybe they'll agree and pay you some lunch money!
- couchand 7y ago> I thought it was best practice to ask the user to click authorize every time even if they're authorizing the same scope they previously authorized? I've never seen an authorization server that works that way. Because I walked to make sure I wasn't missing anything, I went back and reviewed all the guidance I could find on the matter and can't find any reference to the suggestion you make.
- hirsin 7y agoFacebook does this when you sign into an app you've previously authorized, in native application flows. Microsoft just added this recently as well. We do recommend it to other IDPs. This is only enforced for public clients though that don't have verifiable reply URIs - so web sites are OK.
- couchand 7y agoI've only ever implemented web-based OAuth flows, so I haven't seen that behavior. Do they also disallow the use of refresh tokens? It would seem that allowing refresh would let a malicious app get around the requirement.
- diafygi 7y agoHmmm, is there guidance saying that you should auto-redirect? The spec says, "If the authorization server observes multiple attempts to exchange an authorization code for an access token, the authorization server SHOULD attempt to revoke all access tokens already granted based on the compromised authorization code."[1] If an authorization server implements the recommended behavior and an auto-redirect, doesn't that mean that GET requests will no longer be safely considered immutable since they may cause revocation of previous access_tokens? [1]: https://tools.ietf.org/html/rfc6749#section-10.5 https://tools.ietf.org/html/rfc6749#section-10.5
- mrgalaxy 7y ago> Why does Github automatically redirect back the 2nd time without asking the user to authorize again? Other comments here seem to disagree with this, but I think you are correct. In all of my applications with OAuth, I always ask the user to confirm, even if they already authorized. I figure that user should be very aware that they are authorizing a 3rd party. Now I've never actaully seen another system that worked this way (as was pointed out), but I think they are just doing that for user convenience without realizing the security implications.