Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Organizing a secure channel between a Web app and a Native app

This question is kinda complimentary to "Share credentials between native app and web site", as we aim to share secrets in the opposite direction.

TL;TR: how can we securely share the user's authentication/authorization state from a Web Browser app to a Native Desktop app, so the same user doesn't have to authenticate additionally in the Native app?

TS;WM: We are working on the following architecture: a Web Application (with some HTML front-end UI running inside a Web Browser of user's choice), a Native Desktop Application (implementing a custom protocol handler), a Web API and an OAuth2 service, as on the picture.

Initially, the user is authenticated/authorized in the Web Browser app against the OAuth2 service, using the Authorization Code Grant flow.

Then, the Web Browser content can do one-way talking to the Native app, when the user clicks on our custom protocol-based hyperlinks. Basically, it's done to establish a secure bidirectional back-end communication channel between the two, conducted via the Web API.

We believe that, before acting upon any requests received via a custom protocol link from the Web Browser app, the Native app should first authenticate the user (who is supposed to be the same person using this particular desktop session). We think the Native app should as well use the Authorization Code flow (with PKCE) to obtain an access token for the Web API. Then it should be able to securely verify the origin and integrity of the custom protocol data, using the same Web API.

However, it can be a hindering experience for the user to have to authenticate twice, first in the Web Browser and second in the Native app, both running side-by-side.

Thus, the question: is there a way to pass an OAuth2 access token (or any other authorization bearer) from the Web Browser app to the Native app securely, without compromising the client-side security of this architecture? I.e., so the Native app could call the Web API using the identity from the Web Browser, without having to authenticate the same user first?

Personally, I can't see how we can safely avoid that additional authentication flow. Communication via a custom app protocol is insecure by default, as typically it's just a command line argument the Native app is invoked with. Unlike a TLS channel, it can be intercepted, impersonated etc. We could possibly encrypt the custom protocol data. Still, whatever calls the Native app would have to make to decrypt it (either to a client OS API or some unprotected calls to the Web API), a bad actor/malware might be able to replicate those, too.

Am I missing something? Is there a secure platform-specific solution? The Native Desktop app is an Electron app and is designed to be cross-platform. Most of our users will run this on Windows using any supported browser (including even IE11), but ActiveX or hacking into a running web browser instance is out of question.

like image 593
noseratio Avatar asked Mar 25 '19 10:03

noseratio


3 Answers

The best solution : Single Sign On (SSO) using Custom URL Scheme

When I was checking your question, I remembered the Zoom app that I am using in my office. How it works ?

I have my Gmail account linked to a Zoom account (this is account linkage, which is outside the scope of implementation). When I open Zoom app, I can choose the option to login with Gmail. This opens my browser and take me to Gmail. If I am logged in to Gmail, I am redirected back to a page that asking me to launch Zoom app. How this app launch happen ? The application register a custom URL scheme when app get installed and the final redirect in browser targets this URL. And this URL passes a temporary secret, which Zoom application uses to obtain OAuth tokens. And token obtaining is done independent of the browser, a direct call with SSL to token endpoint of OAuth server.

Well this is Authorization code flow for native applications. And this is how Mobile applications use OAuth. Your main issue, not allowing user to re-login is solved. This is SSO in action.

There is a specification which define best practices around this mechanism. I welcome you to go through RFC8252 - OAuth 2.0 for Native Apps.

Challenge

You need to implement OS specific native code for each application distribution. Windows, Mac and Linux have different implementation support for custom URL scheme.

Advice

PKCE is mandatory (in IETF words SHOULD) for all OAuth grant types. There is this ongoing draft which talks about this. So include PKCE for your implementation too.

How PKCE protects token stealing

With PKCE, the redirect/callback response is protected from stealing. Even some other application intercept the callback, the token request cannot be recreated as the PKCE code_verifer is there.

Also, do not use a custom solution like passing secret through another channel. This will make things complicated when it comes to maintenance. Since this flow already exists in OAuth, you can benefit with libraries and guidance.

-----------------------------------------------------

Update : Protecting Token Request

While the custom URL scheme solves the problem of launching the native application, protecting token request can be challenging. There are several options to consider.

- Bind native application launch with a secret shared from browser

When browser based client launch the native client, it can invoke a custom API to generate a secret. This secret acts like a one time password (OTP). User has to enter this value in native app before it obtain tokens. This is a customization on top of Authorization code flow.

- Dynamic client registration & Dynamic client authentication

Embedding secrets into public clients is discouraged by OAuth specification. But as question owner points out, some malicious app may register itself to receive custom URL response and obtain tokens. In such occasion, PKCE can provide an added layer of security.

But still in an extreme case, if malicious app registers the URL plus use PKCE as the original application, then there can be potential threats.

One option is to allow dynamic client registration at the first time of application launch. Here, installer/distribution can include a secret that used along with DCR.

Also, it is possible to use dynamic client authentication through a dedicated service. Here, the application's token request contains a temporary token issued by a custom service. Custom service obtain a challenge from native application. This may be done through totp or a cryptographic binding based on an embedded secret. Also it is possible to utilize OTP (as mentioned in first note) issued through browser, which needs to be copy pasted manually by end user. Once validated, this service issue a token which correlate to the secret. In the token request, native client sends this token along with call back values. This way we reduce threat vectors even though we increase implementation complexity.

Summary

  • Use custom URL scheme to launch the native application
  • Browser app generate a temporary secret shared with a custom service
  • At native app launch, user should copy the secret to native app UI
  • Native app exchange this secret with custom service to obtain a token
  • This second token combined with call back authorization code (issued through custom url scheme) is used to authenticate to token endpoint
  • Above can be considered as a dynamic client authentication
  • Value exposed to user can be a hashed secret, hence original value is never exposed to end user or another client
  • DCR is also an option but embedded secrets are discouraged in OAuth world
like image 170
Kavindu Dodanduwa Avatar answered Oct 16 '22 11:10

Kavindu Dodanduwa


As you mentioned, using a custom protocol handler is not a safe way to pass secrets, since another app may handle your protocol and intercept that secret.

If you are imposing a strict constraint that the communication channel between the native app and the web app is initiated from the web app, and that the native app has not previously established a secure channel (e.g. shared secret which could encrypt other secrets), then it is not possible to safely transmit a secret to the native app.

Imagine if this were possible, then PKCE would be redundant in an OAuth 2.0 Code Flow, since the server could have safely transmitted the access token in response to the authorization request, instead of requiring the code_verifier to be provided with the grant when obtaining the access token.

like image 28
JoeGaggler Avatar answered Oct 16 '22 12:10

JoeGaggler


Just got the following idea. It's simple and while it doesn't allow to fully automate the setup of a secure channel between Web Browser app and the Native app, it may significantly improve the user experience.

We can use Time-based One-Time Password algorithm (TOTP). In a way, it's similar to how we pair a Bluetooth keyboard to a computer or a phone.

The Web Browser app (where the user is already authenticated) could display a time-based code to the user, and the Native app should ask the user to enter that code as a confirmation. It would then use the code to authenticate against the Web API. That should be enough to establish a back-end channel between the two. The life time of the channel should be limited to that of the session within the Web Browser app. This approach might even eliminate the need for a custom protocol communication in the first place.

Still open to other ideas.

like image 2
noseratio Avatar answered Oct 16 '22 13:10

noseratio