Secure in-app keyboard

  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:

  1. Spying on user input made through a standard IME keyboard (such as the system keyboard)
  2. 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

screnrec-flag-secure-leak

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:

button.setBackgroundColor(Color.TRANSPARENT);

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:

private boolean isShowTapsEnabled(Context context) { try { int showTouches = Settings.System.getInt(context.getContentResolver(), "show_touches"); return showTouches == 1; } catch (Settings.SettingNotFoundException e) { return false; } }

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.

  1. Use a dedicated keyboard, embedded as a View in your app. Something simple: a basic QWERTY or a pinpad.
  2. Include protections against accessibility abuse and UI injection.
  3. Use FLAG_SECURE to prevent screen spying.
  4. 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.
  5. 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.

Guardsquare

Table of contents