Again, there is something fundamentally misunderstood here: Philippe's
exploit will not work with a correctly implemented service worker. Also not
in an iframe. Also not if you unregister it and you start a new iframe.

There is no "need to explain yourself several times" and nobody has
"already demonstrated back in January that this approach is not effective",
because a correctly implemented service worker can effectively prevent this
attack. The attacker cannot "run a new flow" and automate getting a token
if the service worker implementation follows the specified guidelines:
*§6.4.2.1*

*    * The application MUST register the Service Worker before running any
code interacting with the user.*

The redirect URI is registered within your application. If you allow any
redirect_uri to be a silent refresh flow (typically in an iframe), you
*must* make it synchronously register the service worker as the first
action on the page, just as any other part of the application (and stopping
that is a whole different attack than XSS). The single-threaded nature of
javascript and synchronous loading of scripts will not let any secret leak
before it has been loaded (and as an additional counter-measure for
half-manual access code leaks, you could add some restriction to remove
auth codes from pages before it is loaded).

Hence my proposal: instead of a demonstration where you test a
possibly incomplete implementation (which, as far as I can see, doesn't
have the fine details that make it fool-proof), I propose to deliver a
proof-of-contest that would follow these guidelines. Before admitting that
"you cannot secure browser-flows only", I'd still want to actually see that
you can do this (which isn't the case from the explanation I read this
far). This whole story can perfectly be all wrong, but it's work checking
first. Let's be pragmatic, right?


Le lun. 28 août 2023 à 14:15, Jim Manico <j...@manicode.com> a écrit :

> *applause*
>
> Sucks you need to explain yourself several times but this is very helpful
> for the community.
>
> On Aug 28, 2023, at 7:52 AM, Philippe De Ryck <
> phili...@pragmaticwebsecurity.com> wrote:
>
> Responses inline.
>
> Still, there is some initial incorrect point that makes the rest of the
> discussion complicated, and partly wrong.
>
>
> I believe the key to make the discussion less complicated is to
> acknowledge that there are two separate issues:
>
> 1. An attacker can potentially obtain tokens from the legitimate
> application
> 2. An attacker can obtain a set of tokens from the AS directly, completely
> independent of any application behavior
>
> Given that the goal is to prevent an attacker from obtaining tokens,
> scenario 1 becomes irrelevant when scenario 2 is a possibility. It would be
> really helpful to analyze the SW approach with this in mind. I’ll add
> comments inline to highlight why this matters.
>
>
> Specifically, §6.4.2.1 says this: *The service worker MUST NOT transmit
> tokens, authorization codes or PKCE code verifier to the frontend
> application.*
>
> Wording should be refined, but the idea is that the service worker is
> to actually restrict authorization codes from even reaching the frontend.
> Of course, easier said than done, but that part happens to be quite easy to
> implement.
>
>
> This is related to both scenarios. If the SW is running, you can indeed
> hide tokens from the main browsing context, which helps to support scenario
> 1. For scenario 2, you need the guarantee that the SW will intercept *all new
> flows*, otherwise the attacker  can run a silent flow. *As long as the SW
> is running* in the main context, I would assume that the attacker can
> indeed not reach the authorization endpoint directly.
>
> The key part above is “as long as the SW is running”. An attacker with the
> ability to run malicious JS can *unregister* the SW that prevents the
> attacker from reaching the authorization endpoint.
>
> I have raised this issue before, and the response back then was that the
> SW is only actually removed after the browsing context reloads, which is
> true. So from the main context, the attacker cannot launch the attack.
> However, when the attacker instantiates a new browsing context (i.e., an
> iframe), the unregistered SW is no longer present, and is thereby not able
> to restrict access to the authorization endpoint.
>
> I address this concern in the talk I have referenced before. This link
> with the time code included (
> https://youtu.be/OpFN6gmct8c?feature=shared&t=1973) points you to the
> exact demo scenario, where I illustrate how an unregistered SW cannot
> prevent access to an endpoint in an iframe. Admittedly, I have not
> implemented a full OAuth client as a SW, but the minimal PoC you see here
> suffices to illustrate the ineffectiveness of this approach.
>
> With this information, the attack scenario becomes the following:
>
>    1. The attacker unregisters the SW in the main browsing context,
>    preventing it from being used in any new browsing context
>    2. The attacker injects a new iframe and points it to the
>    authorization endpoint
>    3. The AS responds with a redirect with the authorization code
>    4. The attacker detects the redirect, copies the authorization code,
>    and aborts the page from loading (so that the authorization code is never
>    exchanged or the SW is never reloaded)
>    5. The attacker extracts the authorization code and exchanges it for
>    tokens
>
>
>
> TL;DR: a SW is not a security mechanism, and the browser cannot guarantee
> that a SW permanently prevents requests to a certain endpoint.
>
>
> This has further impact on much of the other statements:
> *> The main problem with a browser-only client is that the attacker with
> control over the client has the ability to run a silent Authorization Code
> flow, which provides them with an independent set of tokens*
> [...]
> *> **The security differences between a BFF and a browser-only app are
> not about token storage, but about the attacker being able to run a new
> flow to obtain tokens.*
> [...]
> *> Again, the security benefits of a BFF are not about stoken storage.
> Even if you find the perfect storage solution for non-extractable tokens in
> the browser, an attacker still controls the client application and can
> simply request a new set of tokens. *
>
> Truth is: no, you can't start a new authentication flow and get the
> authorization code back in the main thread. I'm talking about the
> redirection scenario, which I'm the most familiar with, but it would
> probably apply to the "message" one as well (which is new to me and seems
> to be ashtoningly legit due to vague "for example" wording in the OAuth2
> spec :-) ).
>
>
> The attack scenario above does not run the redirect scenario in the main
> browsing context, but in an iframe. Opening an iframe instantiates a new
> nested browsing context, where unregistered SWs are not available.
>
>
> The service worker, according to
> https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/fetch_event#description
>  , just intercepts the authorization code, gets a token, and never sends
> it back to the main code.
>
>
> This point is not relevant, since your SW is no longer active when the
> attacker’s authorization code is being returned.
>
>
> But don't trust me on my words: what about demonstrating our claims with
> actual code, and as such create a shorter, simpler, but more constructive
> discussion?
>
>
> I don’t understand where this remark comes from. I have already
> demonstrated back in January that this approach is not effective, and have
> referred to the recording of this presentation numerous times. I stand by
> my demonstration of the ineffectiveness of SW and encourage you to test
> this out yourself. It is as simple as setting up your SW, unregistering it,
> and running an authorization code flow in an iframe. You’ll see that the
> request goes through to the AS, and that your SW is no longer able to stop
> it.
>
>
> The demonstration in its current form would not lead to a successful
> compromise of a good implementation of access tokens handled by a service
> worker.
>
>
> Once again, I refer back to the start of my mail: *it is not about
> protecting existing tokens (scenario 1)**, *it is all about preventing
> the attacker from running a new flow (Scenario 2).
>
>
> I understand that all of this is quite inconvenient, especially if one is
> heavily invested in running browser-only OAuth clients. Unfortunately, it
> is the nature of web-based applications, and doing so requires a complete
> picture of the security implications. That’s exactly what we are working on
> with the specification.
>
>
> Kind regards
>
> Philippe
>
>
> —
> *Pragmatic Web Security*
> *Security for developers*
> https://pragmaticwebsecurity.com/
> _______________________________________________
> OAuth mailing list
> OAuth@ietf.org
> https://www.ietf.org/mailman/listinfo/oauth
>
>

-- 
Yannick Majoros
Valuya sprl
_______________________________________________
OAuth mailing list
OAuth@ietf.org
https://www.ietf.org/mailman/listinfo/oauth

Reply via email to