OWASP / owasp-mastg

The Mobile Application Security Testing Guide (MASTG) is a comprehensive manual for mobile app security testing and reverse engineering. It describes the technical processes for verifying the controls listed in the OWASP Mobile Application Security Verification Standard (MASVS).
https://mas.owasp.org/
Creative Commons Attribution Share Alike 4.0 International
11.77k stars 2.33k forks source link

Proper Android Local Authentication #1665

Closed galapogos closed 4 years ago

galapogos commented 4 years ago

The current MSTG documentation discussing Android Local Authentication offers 2 options:

  1. Confirm Credentials (MSTG-AUTH-1 and MSTG-STORAGE-11)
  2. Biometric Authentication (MSTG-AUTH-8)

Both options use device level credentials, i.e. lock screen PIN/pattern or biometric authentication. This doesn't cover the case where an app may wish to use an app specific passcode.

There are valid use cases for this, as an app may not wish to use device level authentication. For example, the user may have set a weak passcode (e.g. weak pattern or 4 digit PIN) while the app may wish to use enforce a longer 6 digit PIN).

A secure way would be to perform some cryptographic primitive within the Keystore, that is only accessible when producing a valid passcode. This way, the Keystore (hopefully hardware backed) will be the one verifying authentication, which is much less susceptible to runtime tampering. However, from my research (correct me if I'm wrong), the only passcode that's accepted by the Keystore is the system level lock screen PIN, with no support for app-specific ones. In this case, how can secure local authentication be implemented?

What is the recommended way of implementing local authentication using an app-specific passcode?

sushi2k commented 4 years ago

Hi @galapogos. Thanks for the ticket! As far as I can tell this is not possible to set a specific app password as backup for biometric authentication. If biometric authentication it will always ask for the device pin/password. See also https://developer.android.com/training/sign-in/biometric-auth

Using biometric authentication is a convenient and secure way to authenticate locally. After authenticating locally on the device the user need to login to an app, or resume an existing session which again can be re-authenticated via biometric authentication. You are right that the the user might have a weak pin (1234), but if he has a weak pin and you force the user again to set now an additional pin that might be longer the pin will be 123456. So I don't see the additional security benefit of using now another PIN in an app, but additional overhead in terms of complexity of authentication within the app and frustration for the user to remember now another PIN (which is the reason of doing biometric authentication to move away from passwords and PINs). To ensure a longer PIN is set on the device, this can only be properly enforced via an MDM solution.

I would suggest to enforce a proper password policy during registration, when the user logs in the app offers to login via biometrics next time and the authentication mechanism is implemented accordingly to best practices, through for example refresh/access token (and of course 2FA!). This allows a convenient way of authentication that happens in the background without an additional PIN (which would not have much security benefit but definitely reduce convenience for the user).

galapogos commented 4 years ago

Hi @sushi2k, I agree on your comment about the possibility of a longer but just as weak PIN. However, the app is free to implement any PIN strength policy it might have (and therefore blacklist weak ones), regardless of the device PIN requirements.

An app specific PIN might make sense in the case of a secure app (e.g. a banking app) in an uncontrolled device (no MDM) that either does not support biometric authentication, or isn't set up. In this case, the app cannot rely on an MDM enforcing a device credential policy since it does not control the device, but it should still enforce it within the app.

sushi2k commented 4 years ago

Hi @galapogos. I think for authentication, especially for apps that have sensitive data we should rely on:

All devices for all public apps are unmanaged/uncontrolled but with the items above you can enforce the current best practices (at the least the ones I can think of out of my head). Setting now an additional PIN in an app, has not much security benefit in my opinion. Additionally it would rely on custom code as to the best of my knowledge there is no library or function in iOS/Android that would support something like this. Creating your own crypto code usually will fail and will become very troublesome to maintain. As long as the security control (and I assume it's within the app what you are proposing) is within the app it can always be bypassed through dynamic instrumentation (Frida) or binary patching with Ghidra etc. Therefore I would focus on strong server-side controls for authentication and implement additional best practices within the app that are supported by the OS and programming language you are using.

Please also keep in mind that at the end of the day someone still need to be able to use the app (conveniently). Of course we can throw as many security controls in and make it super complex (and maybe a bit more secure), but do we really reduce the risk with an app specific PIN?

sushi2k commented 4 years ago

Hi @galapogos. After discussing with @commjoen, he brought up a few more points (which concludes for us to close this ticket):

The only solution that can basically detect local tampering without easy patching is the iOS KeyStore. Therefore anything that is offline/local will have to use that and the passcode that comes with it. Any other mechanism, would require an online version at which the server is used.

If it needs to be offline/local, then all you can do is rely and use OS based methods. Otherwise authentication that involves the server-side is the preferred option.

If you want to use and protect an additional PIN, use a long verifier stored encrypted and secured + your pin. Use HBKDF2 with 500.000 rounds or ARGON2ID with high settings and use that as a possible key to decrypt the key stored in they keychain to do local authentication. Still an attacker will be able to get the PIN. Once the attacker has found the salt, all the attacker needs to do is check 1.000.000 (for 6 digit pin) per salt of these rounds to make a rainbow table of keys and get the PIN.

Please note: this also means your Pixel 3 or latest iPhone will take about 10 seconds to authenticate. Any other device even longer and the attacker always has more computation power. So once the attacker has it, the attacker can easily get there, depending on your threatmodel.

Best practice is always: start with low risk items locally (then you could have a simple secured salt of 32 bytes and just 6 digit pin with far lesser amount of rounds), but still, it would be wise to involve the server on any high risk. Question is: if the risk bar is so low, would you even need additional local app pin or just go with the OS local auth?