Secure in-app keyboard
Guardsquare recommended technique
Technique summary | |
Technique | Secure keyboard |
Against | Screen recording, malicious keyboard, and UI injection attacks |
Limitations | None |
Side effects | May reduce user's functionality compared to the standard keyboard |
Recommendations | Recommended for use on Android API Level ≤ 30 (Android ≤ 11) |
A secure in-app keyboard for Android apps is a specialized keyboard designed to enhance security and privacy when users input sensitive information within a mobile application. Unlike standard keyboards, which might be susceptible to various forms of interception, a secure keyboard app is specifically engineered to mitigate these risks. By using a secure keyboard for Android, developers can prevent unauthorized access, reducing the risk of data breaches or theft. Many in-app secure keyboards also feature encryption and do not store user input, adding another layer of protection.
Applicable risks
Secure keyboard helps mitigate two types of risks:
- Spying on user input made through a standard IME keyboard (such as the system keyboard)
- Spying on user input made through a malicious keyboard that is specifically created for spying purposes
Standard IME keyboards usually have broad privileges, which potentially exposes them to different kinds of attacks targeting supply chain, clipboard, network traffic, logs, accessibility events, screen, and more.
When a user is tricked into installing a malicious keyboard, no additional attack channels are required. A malicious keyboard can sniff and exfiltrate the keystrokes entered on the device, and reuse them in a later attack.
Spying on the system keyboard
Left: Unprotected view. Right: Protected view leaking information through the keyboard.
In Android ≤11 the standard keyboard may leak information about keypresses. Screen recording, accessibility services, and other channels, may allow the attacker to exfiltrate the keystrokes.
You can solve this problem by applying the FLAG_SECURE
to the keyboard.
Creating a secure keyboard
There are two major pathways to creating a secure keyboard. You can either design a fully functional keyboard that would implement a standard input method editor (IME) specification, or create an in-app keyboard that is implemented as a View
.
Creating standard IME editors
Creating a standard IME keyboard has a number of disadvantages when used for the security purposes, the most important being that it does not protect the user from the risk of being tricked into using a different, malicious keyboard. Combined with the effort and complexity of implementing a standard IME, this solution ends up ineffective.
This article will not go into further details on creating IME. If this is a preferred solution for your case, use the Google's guide on creating IME for further guidance.
Creating a fully custom in-app keyboard
With a custom keyboard you have full control over the security implementation and the user interface of your secure data entry. These are determined by the purpose of your keyboard. For example, if your goal is to enter a six-digit PIN code securely, you do not have to implement a fully-featured custom keyboard with language capabilities and autocomplete. Instead, it is sufficient to implement a secure PIN pad, which would save effort, tighten security, and result in a better UX.
In the next sections, you will go through typical risks of a custom keyboard application, and the ways to mitigate them.
Visual effect on touches
Attack: screen recording
Defense: FLAG_SECURE
The first scenario consists of a pinpad where, every time a key is touched, a visual feedback is produced, indicating which key was touched. If the screen is being spied on, the entered digits will be leaked.
TODO: The images go here Captured screen when keystrokes produce a visual effect Captured screen when keystrokes produce a visual effect and FLAG_SECURE is set
Thus, the defense here would be to apply FLAG_SECURE
. Considering that there are means for an attacker to disable FLAG_SECURE
, such as through runtime instrumentation or app repackaging, these visual effects should be avoided.
These visual effects on a button can be removed, for example, as follows:
Static pinpad: no visual effect on touches + FLAG_SECURE
Attack: screen recording + show_touches (show taps)
Defense: check show_touches
When no visual effect is produced on keystrokes, visual feedback could still be generated by a privileged attacker through the show_touches (or show taps) option. This would be enough if FLAG_SECURE
is not applied. But if it is, it is still possible to retrieve the entered digits as long as the pinpad is static, such as in a fixed position in the screen, or its digits not changing after every touch. If the attacker knows how the pinpad looks and where it lies, they can easily determine the digits by observing the position of the taps and knowing, from observation, where the pinpad is located in-screen.
TODO: images Captured screen when digits are entered with FLAG_SECURE
applied and show-taps is enabled
TODO: images Reconstruction of the entered digits when the pinpad is static
As a consequence, static keyboards should be avoided for entering secrets. Furthermore, the show-taps option should be checked and abort the operation in case that it is enabled. This check can be done as follows:
Dynamic pinpad: no visual effect on touches + FLAG_SECURE
Attack: screen recording + show_touches (show taps) + disable FLAG_SECURE
Defense: check show_touches
In order to prevent the kind of guessing shown above, we need to introduce some randomness. For instance, we can place the pinpad at a random position after every touch, or shuffle its digits in a random order. This will make it impossible for the attacker to recognize a particular digit from a tap. This is useful also against UI-injection attacks.
Pinpad shifting
TODO: images Captured screen when the pinpad is shifted Captured screen when the pinpad is shifted and FLAG_SECURE is set
Key shuffling
TODO: images Captured screen when the pinpad keys are shuffled Captured screen when the pinpad keys are shuffled and FLAG_SECURE is set
Once again, note that FLAG_SECURE
could be disabled by an attacker, which will break the protection introduced by the randomness. For better security, we need to check if the show-taps option is enabled. This will create a new obstacle for the attacker.
Take-aways
When your app needs to take secrets entered by the user, there is a list of practices that can guide you. We don’t talk here about other types of authentication such as biometrics, just the cases where the user enters secrets themselves such as a PIN code.
- Use a dedicated keyboard, embedded as a View in your app. Something simple: a basic QWERTY or a pinpad.
- Include protections against accessibility abuse and UI injection.
- Use
FLAG_SECURE
to prevent screen spying. - Your keyboard should not be static. You can introduce randomness by placing the keyboard at a random position every time, or by shuffling the keys.
- There are ways to disable
FLAG_SECURE
, you should also periodically check if the show-taps option is enabled and, in such a case, abort the operation.