En este artículo se describe cómo puedes personalizar la protección contra manipulaciones de Google Play para tus aplicaciones y juegos. Si quieres usar las funciones de personalización descritas, activa la protección automática con protección contra manipulaciones en Play Console.
Acerca de la protección contra manipulaciones personalizada
La protección contra manipulaciones personalizada te permite identificar métodos específicos de Java y Kotlin en tu aplicación que requieren una seguridad más sólida. Cuando subas tu versión a Play, Google Play dará prioridad a la protección mejorada de esos métodos específicos.
Al identificar los métodos que requieren una protección mejorada, puedes reforzar la defensa de tu aplicación contra manipulaciones. También puedes usar la protección de métodos para evitar la filtración de secretos de cliente de tu archivo binario (por ejemplo, claves sensibles o URLs que deben incluirse en el cliente).
Configurar la protección contra manipulaciones personalizada
Sigue estos pasos para implementar una protección contra manipulaciones personalizada en el código base de tu aplicación.
Paso 1: Añade la interfaz de protección automática a tu código base
Primero, añade la interfaz de protección a tu aplicación o juego.
Kotlin:
package com.google.android.play.protections.annotations/**
* Describe que un método es apto para la protección mejorada.
*
* <p>Esta anotación se eliminará automáticamente del código dex de tu
* bundle en el momento en que Google Play lo proteja. Úsala solo como
* una anotación a nivel de método. No se admite su uso de ninguna otra forma (por ejemplo, para acceder a la clase
* de forma reflexiva durante el tiempo de ejecución).
*/
@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;
/**
* Describe que un método puede ser apto para la protección mejorada.
*
* <p>Esta anotación se eliminará automáticamente del código dex de tu
* bundle en el momento en que Google Play lo proteja. Úsala solo como
* una anotación a nivel de método. No se admite su uso de ninguna otra forma (por ejemplo, para acceder a la clase
* de forma reflexiva durante el tiempo de ejecución).
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PlayAutomaticIntegrityProtection {}
# Conserva la clase de anotación y sus elementos.
-keep class com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection* { *; }
# De forma predeterminada, ProGuard trata los atributos de las anotaciones como opcionales y los quita
# en el paso de ofuscación. Esta regla asegura que los conserve.
-keepattributes RuntimeVisibleAnnotations, AnnotationDefault
# Conserva los métodos con la anotación, pero permite que se ofusquen.
-keepclassmembers,allowobfuscation class * {
@com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection *;
}
Paso 2: Anota los métodos para la protección personalizada
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun myMethod() {
// Method body...
}
Java
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public void myMethod() {
// Method body...
}Paso 3: (Opcional) Protege los secretos del lado del cliente
La protección de métodos personalizados ofusca (oculta) el código directamente en el cuerpo del método anotado. Esto te puede servir para proteger claves de API sensibles.
Kotlin:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun callApi() {
api.connect("YOUR_API_KEY")
}
Java:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public static void callApi() {
api.connect("YOUR_API_KEY");
}
Paso 4: (Opcional) Gestiona la sobrecarga de rendimiento de la protección
De forma predeterminada, llamar a un método de protección añade una sobrecarga de varios milisegundos. Por lo tanto, no se debe llamar en situaciones en las que el rendimiento sea importante ni en el hilo principal.
Si necesitas proteger un método en el que se requiera una ejecución rápida, hay otro modo de protección más ligero. Puedes usar un atributo de anotación para acelerar el acceso (se carga cuando se inicia), aunque la protección correspondiente no es tan sólida.
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 este modo, añade el atributo de interfaz al cuerpo de la definición de la anotación original del paso 1:
// Actualización de la definición de la anotación de Kotlin
public annotation class PlayAutomaticIntegrityProtection(
/**
* Si es true, el método anotado se cargará cuando se inicie. Si es "false",
* se cargará bajo demanda.
*
* <p>Si se usa la carga bajo demanda, llamar al método repercutirá en el
* rendimiento. Para la carga al iniciarse, el método permanecerá desofuscado en la memoria
* durante el tiempo de existencia de la aplicación.
*/
val loadAtStartup: Boolean = false
) {}
Paso 5: Prueba tu aplicación
Prácticas recomendadas para seleccionar métodos
Elegir los métodos detenidamente implica una protección general más eficaz. Si cada lanzamiento tiene un método de protección nuevo, esa versión de la aplicación o del juego será más resistente a los ataques.
Como norma general, para evitar afectar al rendimiento de la aplicación, selecciona métodos fríos en lugar de métodos calientes. Para obtener la máxima protección, selecciona métodos que:
- Sean imprescindibles para la aplicación (la aplicación no funcionaría si se eliminaran).
- No se ejecuten en el hilo principal o de UI.
- Se ejecuten más de una vez durante el tiempo de existencia de la aplicación, pero no en un bucle caliente.
- No sean triviales (métodos que contengan código o datos no triviales).
- No se ejecuten durante el inicio, si es posible.
- Se hayan refactorizado en gran medida o introducido en la versión.
- No sean abstractos, de interfaz ni constructores.
- No usen la reflexión ni carguen directamente una biblioteca nativa.
Quitar la protección personalizada
Si ya no quieres proteger un método específico, puedes quitar la anotación @PlayAutomaticIntegrityProtection().