Skip to content

MASTG-TEST-0003: Teste de Logs para Dados Sensíveis

Deprecated Test

This test is deprecated and should not be used anymore. Reason: New version available in MASTG V2

Please check the following MASTG v2 tests that cover this v1 test:

Visão Geral

Este caso de teste tem como objetivo identificar dados sensíveis da aplicação em logs do sistema e da aplicação. As seguintes verificações devem ser realizadas:

  • Analisar o código-fonte em busca de código relacionado à geração de logs.
  • Verificar o diretório de dados da aplicação em busca de arquivos de log.
  • Coletar mensagens e logs do sistema e analisá-los em busca de dados sensíveis.

Como recomendação geral para evitar possíveis vazamentos de dados sensíveis da aplicação, as instruções de log devem ser removidas das versões de produção, a menos que sejam consideradas necessárias para a aplicação ou explicitamente identificadas como seguras, por exemplo, como resultado de uma auditoria de segurança.

Análise Estática

As aplicações costumam usar a Classe Log e a Classe Logger para criar logs. Para descobrir isso, você deve auditar o código-fonte da aplicação em busca de tais classes de log. Elas podem ser encontradas pesquisando pelas seguintes palavras-chave:

  • Funções e classes, como:

    • android.util.Log
    • Log.d | Log.e | Log.i | Log.v | Log.w | Log.wtf
    • Logger
  • Palavras-chave e saída do sistema:

    • System.out.print | System.err.print
    • logfile
    • logging
    • logs

Ao preparar a versão de produção, você pode usar ferramentas como Proguard (incluída no Android Studio). Para determinar se todas as funções de log da classe android.util.Log foram removidas, verifique o arquivo de configuração do ProGuard (proguard-rules.pro) em busca das seguintes opções (de acordo com este exemplo de remoção de código de log e este artigo sobre como habilitar o ProGuard em um projeto do Android Studio):

-assumenosideeffects class android.util.Log
{
  public static boolean isLoggable(java.lang.String, int);
  public static int v(...);
  public static int i(...);
  public static int w(...);
  public static int d(...);
  public static int e(...);
  public static int wtf(...);
}

Observe que o exemplo acima apenas garante que as chamadas aos métodos da classe Log serão removidas. Se a string que será registrada for construída dinamicamente, o código que constrói a string pode permanecer no bytecode. Por exemplo, o seguinte código emite implicitamente um StringBuilder para construir a instrução de log:

Exemplo em Java:

Log.v("Private key tag", "Private key [byte format]: " + key);

Exemplo em Kotlin:

Log.v("Private key tag", "Private key [byte format]: $key")

O bytecode compilado, no entanto, é equivalente ao bytecode da seguinte instrução de log, que constrói a string explicitamente:

Exemplo em Java:

Log.v("Private key tag", new StringBuilder("Private key [byte format]: ").append(key.toString()).toString());

Exemplo em Kotlin:

Log.v("Private key tag", StringBuilder("Private key [byte format]: ").append(key).toString())

O ProGuard garante a remoção da chamada do método Log.v. Se o restante do código (new StringBuilder ...) será removido depende da complexidade do código e da versão do ProGuard.

Isso representa um risco de segurança porque a string (não utilizada) vaza dados em texto simples na memória, que podem ser acessados por meio de um depurador ou despejo de memória.

Infelizmente, não existe uma solução definitiva para esse problema, mas uma opção seria implementar uma facilidade de log personalizada que receba argumentos simples e construa as instruções de log internamente.

SecureLog.v("Private key [byte format]: ", key);

Em seguida, configurar o ProGuard para remover suas chamadas.

Análise Dinâmica

Use todas as funções do aplicativo móvel pelo menos uma vez, depois identifique o diretório de dados da aplicação e procure por arquivos de log (/data/data/<nome-do-pacote>). Verifique os logs da aplicação para determinar se dados de log foram gerados; alguns aplicativos móveis criam e armazenam seus próprios logs no diretório de dados.

Muitos desenvolvedores de aplicativos ainda usam System.out.println ou printStackTrace em vez de uma classe de log adequada. Portanto, sua estratégia de teste deve incluir toda a saída gerada enquanto o aplicativo está iniciando, executando e fechando. Para determinar quais dados são impressos diretamente por System.out.println ou printStackTrace, você pode usar o Logcat conforme explicado no capítulo "Testes Básicos de Segurança", seção "Monitorando Logs do Sistema".

Lembre-se de que você pode direcionar um aplicativo específico filtrando a saída do Logcat da seguinte forma:

adb logcat | grep "$(adb shell ps | grep <nome-do-pacote> | awk '{print $2}')"

Se você já conhece o PID do aplicativo, pode fornecê-lo diretamente usando a flag --pid.

Você também pode querer aplicar filtros adicionais ou expressões regulares (usando as flags de regex do logcat, por exemplo -e <expr>, --regex=<expr>) se esperar que certas strings ou padrões apareçam nos logs.