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= 1TYPE_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:
TYPE_MASK_CLASS=0x0000000F(para extrair a parte da classe)TYPE_MASK_VARIATION=0x00000FF0(para extrair a parte da variação)TYPE_MASK_FLAGS=0x00FFF000(para extrair a parte das flags)
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%