Biometric Authentication in Android
The most important methods which must be used in order to implement the biometric authentication in Android are the following ones:
The cipher referred in the first parameter of the authenticate method should be used in order to decrypt a secret data which has been previously stored in the device. Such cipher can use both asymmetric and symmetric algorithm.
In the following example we are going to create a key for a cipher which uses AES-CBC-PKCS7.
When creating the key for the cipher that will be used in the biometric authentication flow, the most important options are the following ones:
Once the cipher is properly initialised it should be used as an argument for the authenticate method in order to start the biometric authentication flow.
The biometric authentication flow is then managed by the Android platform, and the method onAuthenticationSucceeded is called upon a successful authentication.
It is worth considering that this method can also be called by using hooking techniques and tools such as Frida. The difference between a valid authentication flow and a tampered authentication flow is the BiometricPrompt.CryptoObject.
Indeed, when a valid authentication flow is performed the Android platform properly instantiate the cipher contained within the BiometricPrompt.CryptoObject, and then this must be used to decrypt critical data such as the aforementioned authentication token.
Instead, when this method is called by using hooking techniques the cipher is not properly instantiated and when using it to decrypt the data, an exception will be raised.
This implementation is secure even against hooking techniques because when calling the onAuthenticationSucceeded callback with Frida, the AuthenticationResult object does not contain a valid cipher instance since the used key, that has been defined as accessible only after a biometric authentication, has not been unlocked by the Android OS and the cipher will raise an Exception when trying to decrypt the data.
During the various assessments performed on mobile applications we’ve found different insecure implementation of the biometric authentication that looks like the following one:
This kind of implementation is insecure since does not make use of the BiometricPrompt.CryptoObject contained in the AuthenticationResult object, but it assumes that the authentication has been properly validated since the method onAuthenticationSucceeded has been called and allows the user to enter the application.
It is worth considering that even implementation that makes use of the BiometricPrompt.CryptoObject could be insecure if they do not decrypt data that are necessary to login the user (such as an authentication token, JWTs and so on). Indeed even Exceptions could be captured using hooking techniques and could be ignored in order to continue the application flow.
Biometric Authentication in iOS
The iOS platform introduced the biometric authentication starting from iPhone 5s in 2013. At that time it supported only the fingerprint authentication known as Touch ID.
When Apple released the iPhone X, the Face ID was added as biometric option that could be used to authenticate a user.
The biometric authentication flow is usually implemented with the LocalAuthentication framework. It is worth considering however that the LocalAuthentication framework is an event-based procedure and can be bypassed with hooking techniques and tools such as Frida or Objection.
Unlike Android, the iOS platform allows to save arbitrary data within the Keychain defining the access criteria for every stored item.
In order to implement an effective biometric authentication, it is suggested to use the Keychain methods instead of the LocalAuthentication framework. Such approach consists in storing sensitive data (such as an authentication token) within the Keychain, and defining the proper access criteria so that the data can be used only after a successful biometric authentication.
The canEvaluatePolicy method with the deviceOwnerAuthenticationWithBiometrics flag, returns true only if the hardware to authenticate the user through biometrics is available and if the user has enrolled biometric factors.
When storing sensitive data for a biometric authentication within the Keychain it is recommended to use the following flags:
1) kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly: requires that a passcode is set on the device. The data is accessible only with the device unlocked and it is deleted when the user deactivates the passcode.
2) kSecAccessControlBiometryCurrentSet/kSecAccessControlBiometryAny: requires a user to authenticate with biometrics (e.g. Face ID or Touch ID) before accessing the data in the Keychain item. When using kSecAccessControlBiometryCurrentSet, whenever the user adds a fingerprint or facial representation to the device, it will automatically invalidate the entry in the Keychain. This makes sure that the keychain item can only be unlocked by users that were enrolled when the item was added to the keychain.
The usage of the other flags should be avoided when storing data relative to biometric authentication since they do not mandatory require the usage of biometric factors to retrieve the data when accessing the application.
During the various assessments performed on mobile applications we’ve found different insecure implementation of the biometric authentication that make use of the evaluatePolicy method and are similar to the following one:
This kind of implementation is insecure since does not make use of the Keychain, but it assumes that the authentication has been properly validated since the success condition has been met and allows the user to use the application.
Using hooking techniques or tools such as Frida or Objection this kind of implementation could be bypassed without providing a valid biometric authentication.
It is worth considering that even implementations that make use of the Keychain could be bypassed if the proper flags are not set when storing the data in it.
Specifically the usage of the flag kSecAttrAccessibleWhenUnlockedThisDeviceOnly and kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly should be avoided since they do not require that a passcode has been previously set on the device and does not delete the data when the passcode is disabled. Furthermore if the device has no passcode, the data is always accessible since the device is considered always unlocked.
Finally the usage of the other SecAccessControlCreateFlags, except for the aforementioned kSecAccessControlBiometryCurrentSet/kSecAccessControlBiometryAny should be avoided since they do not mandatory require a biometric authentication. Indeed the device passcode could be used as well.
Conclusions
When implementing biometric authentication on mobile application it is recommended to always use solutions that relies on cryptography and secure hardware such as the Keystore for Android and the Keychain for iOS.
Event-based authentication implementation should be considered insecure since they could be easily bypassed on rooted or jailbroken devices by using hooking techniques or tools such as Frida or Objection.
Highly sensitive applications such as banking apps or financial related applications should always rely on strong implementations when using biometric authentication and they should delete the sensitive data when the biometric set is changed or completely disabled.
Finally, for sensitive applications it is also suggested to implement frameworks in order to enhance their resiliency by detecting rooted/jailbroken device or attacks that make use of hooking techniques in order to reduce the risks of being exploited.
References
Android
https://developer.android.com/training/sign-in/biometric-auth
https://github.com/OWASP/owasp-mstg/blob/master/Document/0x05f-Testing-Local-Authentication.md
iOS
This article is the result of research through the official Android and iOS developer guides, the OWASP Mobile Security Testing Guide (https://owasp.org/www-project-mobile-security-testing-guide/) and the assessment activities on mobile applications performed by Minded Security’s consultants.
Authors
- Michele Tumolo
- Giuseppe Porcu
No comments:
Post a Comment