Skip to content

MASTG-KNOW-0055: Cache do Teclado

Quando os usuários inserem informações em campos de entrada, o software do teclado frequentemente fornece sugestões com base em dados inseridos anteriormente. Esse recurso de preenchimento automático pode ser muito útil para aplicativos de mensagens e outros cenários. No entanto, por padrão, o teclado do Android pode reter (ou "armazenar em cache") o histórico de entrada para oferecer sugestões e preenchimento automático. Em contextos onde dados sensíveis são inseridos (como senhas ou PINs), esse comportamento de cache pode expor inadvertidamente informações sensíveis.

Os aplicativos podem controlar esse comportamento configurando adequadamente o atributo inputType nos campos de entrada de texto. Existem várias maneiras de fazer isso:

Layouts XML:

Nos arquivos de layout XML do aplicativo (normalmente localizados no diretório /res/layout após descompactar o APK), você pode definir o tipo de entrada diretamente no elemento <EditText> usando o atributo android:inputType. Por exemplo, definir o tipo de entrada como "textPassword" desativa automaticamente as sugestões automáticas e o cache:

<EditText
    android:id="@+id/password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/password_hint"
    android:inputType="textPassword" />

Usando o Sistema Tradicional de Views do Android:

Ao criar campos de entrada em código usando o sistema tradicional de views do Android, você pode definir o tipo de entrada programaticamente. Por exemplo, usando um EditText em Kotlin:

val input = EditText(context).apply {
    hint = "Enter PIN"
    inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
}

Usando Jetpack Compose:

Se você estiver desenvolvendo com Jetpack Compose, não usa EditText diretamente. Em vez disso, usa funções composables como TextField ou OutlinedTextField junto com parâmetros como keyboardOptions e visualTransformation para obter um comportamento similar. Por exemplo, para criar um campo de senha sem sugestões:

OutlinedTextField(
    value = password,
    onValueChange = { password = it },
    label = { Text("Enter Password") },
    visualTransformation = PasswordVisualTransformation(),
    keyboardOptions = KeyboardOptions(
        keyboardType = KeyboardType.Password,
        autoCorrect = false
    ),
    modifier = Modifier.fillMaxWidth()
)

Neste exemplo do Compose, o PasswordVisualTransformation() mascara a entrada, e keyboardOptions com KeyboardType.Password ajuda a especificar o tipo de entrada de senha. O parâmetro autoCorrect é definido como false para evitar sugestões.

Internamente, o enum KeyboardType no Jetpack Compose mapeia para os valores inputType do Android. Por exemplo, o KeyboardType.Password corresponde ao seguinte inputType:

KeyboardType.Password -> {
    this.inputType =
        InputType.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
}

Tipos de Entrada Sem Cache

Independentemente do método usado, o aplicativo pode usar os seguintes atributos inputType, quando aplicados a elementos <EditText>, para instruir o sistema a desativar sugestões e impedir o cache para esses campos de entrada:

XML android:inputType Código InputType Nível da API
textNoSuggestions TYPE_TEXT_FLAG_NO_SUGGESTIONS 3
textPassword TYPE_TEXT_VARIATION_PASSWORD 3
textVisiblePassword TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 3
numberPassword TYPE_NUMBER_VARIATION_PASSWORD 11
textWebPassword TYPE_TEXT_VARIATION_WEB_PASSWORD 11

Nota: Nos testes do MASTG, não verificaremos a versão mínima do SDK necessária no Android Manifest minSdkVersion porque estamos considerando testes de aplicativos modernos. Se você estiver testando um aplicativo mais antigo, deve verificar isso. Por exemplo, o nível da API 11 do Android é necessário para textWebPassword. Caso contrário, o aplicativo compilado não honraria as constantes de tipo de entrada usadas, permitindo o cache do teclado.

O atributo inputType é uma combinação bit a bit de flags e classes. A classe InputType contém constantes para flags e classes. As flags são definidas como TYPE_TEXT_FLAG_* e as classes são definidas como TYPE_CLASS_*. Os valores dessas constantes são definidos no código-fonte do Android. Você pode encontrar o código-fonte da classe InputType aqui.

O atributo inputType no Android é uma combinação bit a bit dessas constantes:

  • Constantes de classe (TYPE_CLASS_*): Tipo de entrada (texto, número, telefone, etc.)
  • Constantes de variação (TYPE_TEXT_VARIATION_*, etc.): Comportamento específico (senha, e-mail, URI, etc.)
  • Constantes de flag (TYPE_TEXT_FLAG_*): Modificadores adicionais (sem sugestões, multi-linha, etc.)

Por exemplo, este código em Kotlin:

inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD

Onde:

  • TYPE_CLASS_TEXT = 1
  • TYPE_TEXT_VARIATION_PASSWORD = 128

Resulta em 1 or 128 = 129, que é o valor que você verá no código descompilado.

Como decodificar atributos de tipo de entrada após engenharia reversa:

Para decodificar o valor inputType, você pode usar as seguintes máscaras:

Você pode decodificar rapidamente os valores inputType usando as máscaras e a operação AND bit a bit, por exemplo, em Python:

129 & 0x0000000F  #   1 (TYPE_CLASS_TEXT)
129 & 0x00000FF0  # 128 (TYPE_TEXT_VARIATION_PASSWORD)

Como encontrar dados em cache:

Se você escrever, por exemplo, "OWASPMAS" no campo de senha algumas vezes, o aplicativo irá armazená-lo em cache e você poderá encontrá-lo no banco de dados de cache:

adb shell 'strings /data/data/com.google.android.inputmethod.latin/databases/trainingcachev3.db' | grep -i "OWASPMAS"
OWASPMAS@
OWASPMAS@
OWASPMAS%