3

We are developing an iOS application and server where a user will be able to store some personal information and top up money.

I have been reading about the OAuth Authorization flow using PKCE and seems to be the right thing to do. Still from the user experience point of view I don't like that the iOS app needs to use an external user agent to get the authorization code.

I would like to receive feedback about concretely two points.

Issue 1 - Avoid using a browser at all.

This seems to be what almost every app out there is doing. Checking Facebook, Instagram, Connect and other applications, I am never redirected to a browser to authenticate myself. What is the deal here?

My idea would be to perform a normal REST GET call and catch the Authorization Code in the HTTP redirect response.

According to: https://auth0.com/blog/oauth-2-best-practices-for-native-apps/

The user's browser is the recommended external user agent. Embedded user agents must not be used for authorization requests. Authorization servers may detect and block requests from embedded user agents, as they are unsafe for third parties, such as the authorization server itself. The reason for this is because the app can then access not only the OAuth authorization grant, but also the user's full authentication credentials. The app could then potentially record or use this information maliciously. In addition, embedded user agents don't share authentication state with other apps or the browser and therefore disabling single sign-on benefits.

So the bigger security risk seems to be that the app has direct access to the user credentials.

To mitigate this issue with our iOS apps, my idea was to hash it as soon as the user wants to log in, or even when the user types it in a text field. A good answer about this is described at: https://stackoverflow.com/questions/3391242/should-i-hash-the-password-before-sending-it-to-the-server-side

Still an attacker could catch the hashed PIN. In any case: Which are the real world scenarios where an attacker has access to the mobile device of a victim exactly at the point in time where the user is performing a login?

Issue 2 - Keeping the Access Token safe.

Once an app receives the access and refresh token there is no way to fully protect those tokens from external attackers.

My idea here is to make the BE expose two API scopes:

  • API Scope 1 - Provides READ access to the user's resources only. This API can be accessed using the Access Token. If an attacker manages to get the access token there is no "WRITE" damage they can do to the user's resources.
  • API Scope 2 - Provides WRITE access to the user's resources, for example top up money. For this use case the Access Token is also needed, but the POST request will be signed using Asymmetric PKI. The public key would be sent to the BE during user's registration. Since the signing operations would happen in the device's Secure Enclave (2FA), it would be very hard for an attacker to make the user top up money or any other "WRITE" request.

How does this structure looks like? Thank you.

1 Answer 1

2

Issue 1 - Avoid using a browser at all.

First important thing to understand is that originally, OAuth2 was designed for 3rd-party API access, which is why flows and security models are designed for use by a third party.

However, in your case, it seems that the OAuth2 tokens will be used only by your application.

The Authorization Code flow is indeed the recommended flow for native mobile applications by the RFCs. The main security mechanisms in place are:

  • Use of a redirect URI, to make sure that only the intended application will receive the tokens
  • Use of an authorization token, to mitigate risks of interception of tokens between the browser and the native application (in opposition to the implicit flow, in which it is sent direct in the URI's fragment)
  • Use of PKCE, for the same reasons

However, regarding the first point:

  • Custom URL scheme: you cannot guarantee that another app on the device will claim the Custom URI scheme
  • Universal URI: it involves bad UI and additional complexity

Using the Authorization Code flow has 3 benefits:

  • Single Sign-On (SSO) with other native or web apps using the same authentication service
  • Allow third-party apps using your authentication service (the OAuth2 way) without leaking user credentials (such as password) to the third-party app
  • Some authentication schemes are available only in the browser, such as WebAuthn

However, if it's tour own app, and you don't need SSO, and you think native UI is better, then my opinion is that it is acceptable from a security perspective. You can use the OAuth2 Resource Owner Password credentials if you just need login/password authentication, otherwise you'll have either to extend this OAuth2 flow or to implement it on your own.

Note that since you don't use redirect URIs at all and a mobile app is not capable of keeping a secret, well, secret (called public client in OAuth2 terminology), you basically can't guarantee that it's really your native app that is calling your authentication endpoint.

Therefore, you have 2 solutions:

  • enroll your application with a secret. For instance, it could be a secret that is embedded in a QR-code that is sent by letter to your client
  • protect your authentication API against brute-force attacks, and apply strict throttle limits. In addition, do not allow weak passwords, and / or ask for a second factor for more sensitive data

But since it's your app, and it's unlikely you'll install a keylogger on your own app (!), I see no point hashing the PIN (weak password with low entropy by the way). If your mobile OS is hacked and the "virus" has access to your application memory and code, there's nothing you can do anyway.

Issue 2 - Keeping the Access Token safe.

The best practice is to keep the refresh token in the KeyChain, and the access token in memory. When the access token is lost or expired, just request a new one using the refresh token.

To mitigate risks of stolen tokens for sensitive data, you can:

  • limit the lifetime of such tokens
  • ask for a second factor for such tokens
  • binding them cryptographically to the calling application. This mechanism is called Proof-of-Possession (PoP) and is surprisingly still experimental. You can find more information at: enter link description here and enter link description here
1
  • Also note that some OAuth2 authorization endpoints, such as Google accounts, block webviews. Yours should probably do that too. It's meant to block malicious application from using it and intercepting user credentials.
    – Tangui
    Commented Sep 7, 2019 at 11:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .