Este artigo explica como personalizar a proteção contra adulterações do Google Play para seus apps e jogos. Para usar os recursos de personalização descritos nesta página, é necessário ter a proteção automática e ativar a proteção contra adulterações no Play Console.
Sobre a proteção contra adulterações personalizada
Com a proteção contra adulterações personalizada, é possível identificar métodos específicos de Java e Kotlin no seu app que exigem mais segurança. Quando a versão é enviada ao Google Play, a proteção reforçada é priorizada para esses métodos específicos.
Ao identificar métodos para a proteção reforçada, você pode aprimorar a defesa do seu app contra adulterações. Também é possível usar a proteção de método para evitar a exfiltração de chaves secretas do cliente do seu binário, como chaves ou URLs sensíveis que precisam ser incluídos no cliente.
Configurar a proteção contra adulterações personalizada
Siga estas etapas para implementar a proteção contra adulterações personalizada na base de código do seu app.
Etapa 1: adicionar a interface de proteção automática à base de código
Primeiro, adicione a interface de proteção ao seu app ou jogo.
Kotlin:
package com.google.android.play.protections.annotations/**
* Indica que um método é candidato à proteção reforçada.
*
* <p>Essa anotação será removida automaticamente do código DEX do seu
* pacote após a proteção pelo Google Play. Use apenas como
* uma anotação no nível do método. Qualquer outro uso (por exemplo, acessar a classe
* de forma reflexiva durante o tempo de execução) não está disponível.
*/
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
public annotation class PlayAutomaticIntegrityProtection() {}
Java:
package com.google.android.play.protections.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indica que um método é candidato à proteção reforçada.
*
* <p>Essa anotação será removida automaticamente do código DEX do seu
* pacote após a proteção pelo Google Play. Use apenas como
* uma anotação no nível do método. Qualquer outro uso (por exemplo, acessar a classe
* de forma reflexiva durante o tempo de execução) não está disponível.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PlayAutomaticIntegrityProtection {}
# Mantenha a classe da anotação e os membros dela.
-keep class com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection* { *; }
# Por padrão, o ProGuard trata os atributos da anotação como opcionais e os remove
# na etapa de ofuscação. Esta regra garante que eles sejam mantidos.
-keepattributes RuntimeVisibleAnnotations, AnnotationDefault
# Mantenha quaisquer métodos com a anotação, mas permita que eles sejam ofuscados.
-keepclassmembers,allowobfuscation class * {
@com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection *;
}
Etapa 2: adicionar anotações aos métodos para proteção personalizada
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun myMethod() {
// Corpo do método…
}
Java:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public void myMethod() {
// Corpo do método…
}Etapa 3: (opcional) proteger chaves secretas do cliente
A proteção de método personalizada ofusca (oculta) o código diretamente no corpo do método anotado. Isso pode ser usado para proteger chaves de API sensíveis.
Kotlin:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun callApi() {
api.connect("SUA_CHAVE_DE_API")
}
Java:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public static void callApi() {
api.connect("YOUR_API_KEY");
}
Etapa 4 (opcional): gerenciar a sobrecarga de desempenho da proteção
Por padrão, chamar um método protegido adiciona uma sobrecarga de vários milissegundos. Portanto, ele não pode ser chamado em casos sensíveis ao desempenho ou na linha de execução principal.
Se você precisar proteger um método em que a execução rápida é necessária, um modo de proteção mais leve está disponível. Você pode usar um atributo de anotação para agilizar o acesso (carregado na inicialização), mas essa proteção correspondente não é tão forte.
Kotlin:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
fun callApi() {
api.connect("YOUR_API_KEY")
}
Java:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
public static void callApi() {
api.connect("YOUR_API_KEY");
}
Para usar isso, adicione o atributo de interface ao corpo da definição para a anotação original da etapa 1:
// Atualização da definição para a anotação em Kotlin
public annotation class PlayAutomaticIntegrityProtection(
/**
* Se for verdadeiro, o método anotado será carregado na inicialização. Se for falso, ele
* será carregado sob demanda.
*
* <p>No carregamento sob demanda, a chamada do método vai prejudicar o
* desempenho. No carregamento na inicialização, o método vai continuar desofuscado na memória
* durante todo o ciclo de vida do app.
*/
val loadAtStartup: Boolean = false
) {}
Etapa 5: testar o app
Práticas recomendadas para seleção de métodos
Uma seleção cuidadosa de métodos resulta em uma proteção geral mais forte. Se cada nova versão do app ou jogo tiver um método recém-protegido, ela será mais resistente a ataques.
Como regra geral para não afetar o desempenho do app, selecione métodos frios em vez de quentes. Para proteção máxima, selecione métodos que:
- Sejam essenciais para o aplicativo (ele falharia se fossem removidos).
- Não sejam executados na linha de execução principal/de interface.
- Sejam executados mais de uma vez durante o ciclo de vida do app, mas não em um loop quente.
- Não sejam triviais (métodos que contêm código ou dados não triviais).
- Não sejam executados durante a inicialização, se possível.
- Sejam recém-introduzidos ou muito refatorados na versão.
- Não sejam abstratos, de interface ou construtores.
- Não usem reflexão nem carreguem diretamente uma biblioteca nativa.
Remover a proteção personalizada
Se você não quiser mais proteger um método específico, basta remover a anotação @PlayAutomaticIntegrityProtection().