Categories: Security
There has recently been a strong trend towards forcing the use of a modern mobile phone for authenticating to online banking.
I’ve been rather cautious about this, and currently use a dedicated “tan generator” device which my bank reluctantly offers as an alternative. The principal problem I have with using an application on a phone as an authentication mechanism is:
- a phone typically has many other apps installed on it, and
- phone operating systems have security holes
See in particular this article which lists 193 different security vulnerabilities fixed in a recent Android update. Potentially some of these could allow other apps on the same phone to interfere with banking authorization. Similarly, this article describes security problems fixed in iPhones.
There are signs that this is improving in Android at least, via several technologies:
- phones with embedded security hardware
- the Strongbox API for encryption and authentication
- the Protected Confirmation API
- the Trusted Execution Environment
Google’s Pixel3 mobile phones include a Titan-M security chip. This places the storage of keys within a separate chip with its own CPU. The host cannot access data within the chip directly; instead it invokes an API offered by the security chip and this API offers “encrypt/decrypt data” operations but not “read key”. This architecture ensures that a rogue app on the phone cannot extract security keys from the phone and send them elsewhere.
Standard Android APIs (eg StrongBox) provide encrypt/decrypt support which delegates to the security chip if one is present (otherwise uses less secure local storage).
One remaining problem is that a hostile app can still issue authentication tokens from the phone itself, even if it cannot read the key directly. Android 9 and later provides a solution for this, which together with a physical security chip seems to provide a robust solution. Android devices from v9 onwards provide a “Trusted Execution Environment” (TEE). The TEE is a minimal operating system which runs when the device is started (“Secure OS”); the Android kernel is then booted separately (“Rich OS”). Software in the “Rich” kernel can pass data to the TEE only via a “TEE Driver” running under the Rich environment, which in turn uses hardware-provided features to “switch mode”. The effect is similar to running multiple VMs under a basic hypervisor.
The device manufacturer defines which “applications” run under the TEE. The Android API defines standard APIs for a number of security-sensitive services; under some devices these APIs are implemented by code running under the Rich OS (not robust against root-level attacks on the Android kernel) but more advanced devices implement these APIs by delegating to software running within the TEE. The TEE protects itself on boot by verifying the signature of its kernel against in-hardware keys. One such API is the StrongBox API which creates and stores cryptographic keys.
Another service implemented within the TEE is the Protected Confirmation API (since Android 9 aka Pie released August 2018); an app in the Rich OS can request the Secure OS to prompt the user for confirmation of an operation. The prompt is then confirmed by the user via a hardware-keypress (eg double-click of power button) in a way that the Rich OS cannot emulate. On correct confirmation, the Secure OS then signs the “payload” being confirmed and returns it to the Rich OS app that requested the confirmation. This is a relatively secure solution - provided users are aware of what the “secure confirmation” signal is (eg double-click power button). The most obvious use is in generation of login tokens using a key generated via the StrongBox API.
An open-source implementation of a suitable TEE (“Trusty TEE”) is available (developed primarily by Google staff), which all Android device manufacturers can (optionally) embed in their devices. Technically, Trusty TEE is separate from Android and other implementations can be used with Android if desired.
Even without a hardware security module, the TEE can store keys in a relatively secure manner; no code running under the Rich OS can access data that the TEE has stored on the main storage devices of the phone. However someone with direct access to the storage devices (without booting the device) could potentially extract such keys; having a Titan-M module generate and store keys internally is even more secure.
Of course the big question with proprietary authentication apps provided by banks is: does their implementation correctly use the security features of the host OS? I have worked in IT for many large banks, and know from personal experience that their software quality is often extremely poor.
Another problem is that many banks do not document the security protocol that their authentication application uses. This is very frustrating - as someone with an interest in such things, I would very much like to be reassured they are using a well-tested and standard protocol, and have not just invented something themselves.
So despite all this complexity in Android, I still feel more comfortable using something like a Yubikey where storage of keys is completely separate from the phone and generation of an authentication token requires a physical keypress.
Note that I have experience in encryption and security, but am not particularly familiar with Android. Feedback welcome.