Segurança moderna no Android (parte 4)

Tempo de leitura: 3 minutes

Terminamos a visão geral da Criptografia no Android e é hora de falar sobre como funciona a biometria e como usá-la a seu favor.

No Android 6.0 a privacidade passou a ser uma das prioridades para as equipes móveis, nesta versão, o Google introduziu uma API padronizada para provedores, com foco em impressões digitais adicionando um padrão para eles.

No primeiro volume desta série, falamos de Trusted Execution Environments (TEE), esses espaços fazem parte de todo smartphone moderno, isso significa que as informações biométricas são criptografadas e armazenadas em uma parte separada do telefone, completamente inacessível ao regular sistema operacional. Tornando os dados biométricos não exportáveis, podemos pedir ao TEE que autentique a identidade dos nossos usuários, mas os dados biométricos não são acessíveis, nem injetáveis, tornando a biometria uma forma de autenticação local.

Os telefones evoluíram e agora o Android inclui autenticação biométrica de rosto e impressão digital. O Android pode ser personalizado para oferecer suporte a outras formas de autenticação biométrica, por exemplo, íris. Dentro do código, o Android tem uma classe para lidar com a autenticação biométrica chamada BiometricPrompt que inclui Fingerprint e Face, o Google tem que validar que a implementação biométrica atende a algumas especificações de segurança para ingressar nesta classe, o principado precisa ter uma arquitetura segura isso significa, que os dados biométricos devem viajar em um canal seguro que garante que se o kernel ou a plataforma for comprometida, os dados biométricos brutos não serão vazados e que os dados não podem ser injetados neste canal seguro, e em segundo lugar tem que atender a uma métrica chamada spoofability que é medido por três outras métricas que são descritas no Guia de taxa de aceitação de spoof (SAR) para medir o quão resiliente uma biometria é contra um invasor profissional, inclui:

  • Taxa de aceitação falsa (False Accept Rate) (FAR): mede a frequência com que um modelo aceita por engano uma entrada incorreta escolhida aleatoriamente.
  • Taxa de aceitação do impositor (Imposter Accept Rate) (IAR): mede a possibilidade de um modelo biométrico aceitar dados que imitam os dados originais. Imagine um imitador de um ator ou cantor com um rosto ou voz semelhante.
  • Taxa de aceitação de falsificação (Spoof Accept Rate) (SAR): Mede a possibilidade de um modelo biométrico aceitar dados previamente registrados.

Após esses testes, uma implementação biométrica pode cair em uma destas três categorias:

  • Strong / Forte: SAR (Spoof Accept Rate / taxa de aceitação de falsificação): 0–7% FAR (False accept rate / taxa de aceitação falsa): 1 / 50k FRR (False rejection rate / taxa de rejeição falsa): 10%
  • Weak / Fraco: SAR: 7–20% FAR: 1 / 50k FRR: 10%
  • Convenience / Conveniência: SAR:> 20% FAR: 1 / 50k FRR: 10%

Isso ainda contém o fallback (em horas) para a primeira autenticação, a probabilidade de integração com a classe BiometricPrompt e a possibilidade de usar o KeyStore. Há um documento completo sobre a taxa de queda em sensores biométricos aqui, se você quiser que eu me aprofunde em sensores e sistemas de calibração, por favor, deixe uma mensagem no final deste post.

BiometricPromp em ação

No Android 9, o BiometricPrompt oferece aos desenvolvedores uma nova maneira de lidar com o FingerPrintManager (esta classe já está obsoleta) sem a necessidade de adicionar uma nova IU, o BiometricPrompt permite que os usuários entendam UX / IU simples, tornando-a uma experiência perfeita.

Para começar a usar a classe BiometricPrompt, você pode implementar isso em seu arquivo gradle, é uma implementação bastante direta:

dependencies {
    implementation "androidx.biometric:biometric:1.0.1"
}

Para adicionar um construtor de prompt biométrico, você só precisa criar este construtor

val biometricPromptBuilder = BiometricPrompt.PromptInfo.Builder()
            .setTitle("Um bom título")
            .setSubtitle("Uma legenda melhor")
            .setNegativeButtonText("Cancelar")
            .build()

Precisamos adicionar um novo ouvinte às ações e resultados do usuário, que lhe dará sucesso, falha e erro se o usuário falhar várias vezes para autenticar o prompt biométrico irá bloquear o usuário por alguns minutos até que ele possa tentar novamente , isso acontecerá no retorno de chamada de erro

var biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() {
  override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
      super.onAuthenticationError(errorCode, errString)
      // Error 
  }

  override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
      super.onAuthenticationSucceeded(result)
      // Success
  }

  override fun onAuthenticationFailed() {
      super.onAuthenticationFailed()
      // Failed
  }
})

Se você tiver algum problema com a implementação, há uma postagem de blog completa de Sam Edwards (Sam Edwards) em seu blog: https://handstandsam.com/2020/05/07/unlocking-biometric-prompt-fingerprint-face-unlock /

 

Adicionando prompt biométrico à sua criptografia

Na segunda parte desta série, falamos sobre a possibilidade de criar seu próprio KeyPairGenerator, mesmo se você não estiver usando Jetpack Security, você pode adicionar a linha 7 na próxima essência para garantir que os usuários tenham qualquer tipo de segurança:

KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore").apply {
    val certBuilder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT)
        .setKeyValidityStart(keyValidityStart)
        .setKeyValidityEnd(keyValidityEnd)
        .setCertificateSerialNumber(BigInteger.valueOf(1L))
        .setCertificateSubject(X500Principal("CN=MyCompany"))
        .setUserAuthenticationRequired(true)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        initialize(
            certBuilder
                .setIsStrongBoxBacked(true) 
                .build()
        )
    } else {
        initialize(certBuilder.build())
    }
}.also {
    val keyPair = it.generateKeyPair()
    //Continue here
}

Você pode usar uma chave secreta que permite usar as credenciais biométricas para um período de validade específico, durante esse período, seu aplicativo pode executar várias operações criptográficas sem que o usuário precise reautenticar, você também pode fazer isso ao criar sua chave mestra para Jetpack Security

val spec = KeyGenParameterSpec.Builder(
       KEY_NAME,
       KeyProperties.PURPOSE_ENCRYPT or
       KeyProperties.PURPOSE_DECRYPT
   ).apply {
       setBlockModes(KeyProperties.BLOCK_MODE_CBC)
       setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
       setUserAuthenticationRequired(true)
       setUserAuthenticationValidityDurationSeconds(TIMEOUT_SECONDS)
       setRandomizedEncryptionRequired(false)
   }.build()

val masterKeyAlias = MasterKeys.getOrCreate(spec)

 

Isso é tudo para esta parte da postagem, se você precisar de ajuda:

 

Visits: 1 Visits: 1200509