Re: [OAUTH-WG] draft-parecki-oauth-browser-based-apps-00

David Waite <david@alkaline-solutions.com> Thu, 08 November 2018 21:59 UTC

Return-Path: <david@alkaline-solutions.com>
X-Original-To: oauth@ietfa.amsl.com
Delivered-To: oauth@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 79713130934 for <oauth@ietfa.amsl.com>; Thu, 8 Nov 2018 13:59:20 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.9
X-Spam-Level:
X-Spam-Status: No, score=-1.9 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MzEsa-tsCprR for <oauth@ietfa.amsl.com>; Thu, 8 Nov 2018 13:59:18 -0800 (PST)
Received: from alkaline-solutions.com (lithium5.alkaline-solutions.com [173.255.196.46]) by ietfa.amsl.com (Postfix) with ESMTP id 9D72912D4E8 for <oauth@ietf.org>; Thu, 8 Nov 2018 13:59:18 -0800 (PST)
Received: from [IPv6:2601:282:202:b210:3cb7:7c78:650b:98d] (unknown [IPv6:2601:282:202:b210:3cb7:7c78:650b:98d]) by alkaline-solutions.com (Postfix) with ESMTPSA id ED63C31689; Thu, 8 Nov 2018 21:59:17 +0000 (UTC)
Content-Type: text/plain; charset="utf-8"
Mime-Version: 1.0 (Mac OS X Mail 12.2 \(3445.102.3\))
From: David Waite <david@alkaline-solutions.com>
In-Reply-To: <710899611.302780.1541675954453@mail.yahoo.com>
Date: Thu, 08 Nov 2018 14:59:16 -0700
Cc: oauth <oauth@ietf.org>, Hannes Tschofenig <Hannes.Tschofenig@arm.com>
Content-Transfer-Encoding: quoted-printable
Message-Id: <9829E15A-416C-489E-A48D-58B771F6FFDA@alkaline-solutions.com>
References: <VI1PR0801MB211299BED6B61582DC33B873FACB0@VI1PR0801MB2112.eurprd08.prod.outlook.com> <710899611.302780.1541675954453@mail.yahoo.com>
To: Tomek Stojecki <tstojecki=40yahoo.com@dmarc.ietf.org>
X-Mailer: Apple Mail (2.3445.102.3)
Archived-At: <https://mailarchive.ietf.org/arch/msg/oauth/iZ3rkx5a4N7-iZLoC-tRN74Xr1A>
Subject: Re: [OAUTH-WG] draft-parecki-oauth-browser-based-apps-00
X-BeenThere: oauth@ietf.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: OAUTH WG <oauth.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/oauth>, <mailto:oauth-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/oauth/>
List-Post: <mailto:oauth@ietf.org>
List-Help: <mailto:oauth-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/oauth>, <mailto:oauth-request@ietf.org?subject=subscribe>
X-List-Received-Date: Thu, 08 Nov 2018 21:59:20 -0000


> On Nov 8, 2018, at 4:19 AM, Tomek Stojecki <tstojecki=40yahoo.com@dmarc.ietf.org> wrote:
> 
> Thanks for putting this together Aaron. 
> 
> Having read through the document, I am not as convinced that there is enough of a benefit of Authorization Code + PKCE vs Implict Flow for SPAs.
> 
> In section 7.8. the document outlines the Implicit flow disadvantages as following:
> 
> "- OAuth 2.0 provides no mechanism for a client to verify that an access token was issued to it, which could lead to misuse and possible impersonation attacks if a malicious party hands off an access token it retrieved through some other means to the client."
> 
> If you use Code + PKCE with no client secret (public client) as it is being advocated, you can't verify the client either. PKCE is not for authenticating the client, it is there to provide a mechanism to verify inter-app communication, which occurs between a browser and a native app. There is no inter-app communication in implicit (everything stays in the browser), so no need for PKCE.

Use of a fixed set of uniquely resolvable redirect URIs (e.g. not localhost, not arbitrarily registrable custom URI schemes) does provide an addressable channel to the public client for codes and implicit tokens. I should not be able to make a client that can reuses the public identifier as a third party, because I cannot catch the response URL from the authorization endpoint.

The difference is with implicit, the first party client cannot verify the tokens were meant for the client (or really even that they came from the AS). With code, you are contacting the AS and doing an exchange based on the code and your public client identifier.

In the sense of pure OAuth, where no authentication or additional authorization decisions are made based on the access token, the issuer and audience client could be checked via an introspection endpoint - but if you are using pure OAuth and not relying on things like CORS restrictions for your security model, it shouldn’t matter.

For OpenID Connect and cases where you are going beyond a pure authorization model (perhaps by having API access restricted by CORS), this sort of check is important. You could trust clients to explicitly check by looking in an id_token (when available) or calling an introspection endpoint, or you could have this check happen as part of normal flow by using code flow.

PCKE does not resolve any known code injection attacks for SPA public clients. Recommending administrators require PKCE does allow them to start to make a single coherent policy for public clients.

A consistent policy also helps in SPA/native app crossover cases. For examples, a javascript app could be published as a native app via wrapping in a Cordova-style toolset, or by sharing a significant amount of code using a React-native style toolset. Both the SPA and native app could then share handling links depending on native app installation due to universal/app link features of the operating systems. For this reason, there was a definite effort to propose best practices that overlapped with the native app BCP.

It is also worth noting that since the SPA and native app could share the same client identifier and redirect handling (via universal links), you *could* have code injection, but it would be between multiple first-party apps.

> "- Supporting the implicit flow requires additional code, more upkeep and understanding of the related security considerations, while limiting the authorization server to just the authorization code flow simplifies the implementation."
> 
> This is subjective and can be easily argued the other way. I think one of the main selling points behind implicit was its simplicity. It is hard to argue (putting libraries aside) that making one redirect (implicit) requires more code, work, etc.. than making a redirect and at least two additional calls in order to get AT (plus CORS on AS side).

The implicit flow is only simpler for clients until they have to get a new access token. Typically then you need a different set of OAuth code to request a new token in the background via a hidden iframe, failing back to temporarily leaving the app via top-level redirect. There are also cases where the safari browser detects this cross-domain iframe bouncing as a tracker and segments any AS cookies/storage per client site.

It is more work for the AS to support both. You may also wind up having different security models for the two different public client flows. In particular, you may find yourself as an AS policy setter wanting to have longer lived sessions for implicit clients which do not have refresh tokens to extend access token validity in the background. For this reason, you may also decide implicit clients cannot get access to the same scopes that a code client can. 

There are also gotchas people are not used to in implicit, such as fragment identifiers being preserved on redirects.

For OpenID Connect, getting the id_token on a back-end call means that there is still transport-level security of the value if clients ignore the signature. Again, you could trust your clients to explicitly add signature verification code for id_tokens and access token hashes, as well as verify the token issuer and audience - or you could have a baseline level of security by using the code flow.

> Further, in the beginning paragraph of 7.8, you mention that implicit gets the AT through the front-channel. Exchanging code for AT will also happen in the browser , where instead of a url you will have an xhr (and again, now we have cors)
> 
> Finally, how is the AT going to be refreshed? Are we allowing for long lived RT in the browser? I see that the document mentions CSP in 7.7, but doesn't the same apply to securing AT with Implicit?

Refresh tokens are used for two different purposes, and this might be worth clarifying for those setting their security policy:

1. refresh tokens for “offline” access, meaning that the client may perform actions on the user’s behalf while the user isn’t around. Typically, this means the refresh token lasts until the user or AS revokes it, so authorization thus also remains until revoked.
2. refresh tokens as a signaling method for re-authentication. In this case, the idea is that tokens are being used “online” as part of user interaction, with the application being forced to send the user to the AS to re-authenticate when the access token can no longer be refreshed. If the AS can track consent to the client (by a unique client identifier or via a mechanism like id_token_hint), this re-authentication may still require no user interaction.

For public clients, I see us using the second “online” refresh tokens. Whether they are long-lived or not really depends on the AS policy for re-authentication. If the client is being run on a device falling under corporate management, the AS might decide to make those particular refresh tokens last indefinitely.

-DW