Questo articolo descrive come personalizzare la protezione dalle manomissioni di Play per le tue app e i tuoi giochi. Per utilizzare le funzionalità di personalizzazione descritte in questa pagina, devi aver attivato la protezione automatica con la protezione dalle manomissioni in Play Console.
Informazioni sulla protezione dalle manomissioni personalizzata
La protezione dalle manomissioni personalizzata ti consente di identificare metodi Java e Kotlin specifici all'interno della tua app che richiedono una maggiore sicurezza. Quando la release viene caricata su Play, Google Play dà la priorità alla protezione avanzata di questi metodi specifici.
Identificando i metodi che richiedono una protezione avanzata, puoi migliorare la difesa della tua app dalle manomissioni. Puoi anche utilizzare la protezione dei metodi per proteggerti dall'esfiltrazione dei client secret dal tuo file binario (ad esempio, chiavi o URL sensibili che devono essere inclusi nel client).
Configura la protezione dalle manomissioni personalizzata
Segui questi passaggi per implementare la protezione dalle manomissioni personalizzata nel codebase della tua app.
Passaggio 1: aggiungi l'interfaccia di protezione automatica al tuo codebase
Innanzitutto, aggiungi l'interfaccia di protezione alla tua app o al tuo gioco.
Kotlin:
package com.google.android.play.protections.annotations/**
* Indica che un metodo è idoneo per la protezione avanzata.
*
* <p>Questa annotazione verrà rimossa automaticamente dal codice dex del tuo
* bundle nel momento in cui Google Play protegge il bundle. Utilizzala solo come
* annotazione a livello di metodo. Qualsiasi altro utilizzo (ad es. l'accesso alla classe
* in modo riflessivo durante il tempo di esecuzione) non è supportato.
*/
@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 che un metodo è idoneo per la protezione rafforzata.
*
* <p>Questa annotazione verrà rimossa automaticamente dal codice dex del tuo
* bundle nel momento in cui Google Play protegge il bundle. Utilizzala solo come
* annotazione a livello di metodo. Qualsiasi altro utilizzo (ad es. l'accesso alla classe
* in modo riflessivo durante il tempo di esecuzione) non è supportato.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PlayAutomaticIntegrityProtection {}
# Mantieni la classe di annotazione e i relativi elementi.
-keep class com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection* { *; }
# Per impostazione predefinita, ProGuard considera gli attributi di annotazione come facoltativi e li rimuove
# durante il passaggio di offuscamento. Questa regola ne garantirà la conservazione.
-keepattributes RuntimeVisibleAnnotations, AnnotationDefault
# Mantieni i metodi con l'annotazione, ma consentine l'offuscamento.
-keepclassmembers,allowobfuscation class * {
@com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection *;
}
Passaggio 2: annota i metodi che richiedono la protezione personalizzata
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun myMethod() {
// Corpo del metodo…
}
Java:
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public void myMethod() {
// Corpo del metodo…
}(Facoltativo) Passaggio 3: proteggi i secret lato client
La protezione personalizzata dei metodi offusca (nasconde) il codice direttamente all'interno del corpo del metodo annotato. Puoi utilizzarla per proteggere le chiavi API sensibili.
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");
}
(Facoltativo) Passaggio 4: gestisci l'overhead delle prestazioni della protezione
Per impostazione predefinita, la chiamata di un metodo protetto aggiunge un overhead di diversi millisecondi. Pertanto, non deve essere chiamato in scenari in cui le prestazioni sono importanti o nel thread principale.
Se devi proteggere un metodo in cui è necessaria un'esecuzione rapida, è disponibile una modalità di protezione più leggera. Puoi utilizzare un attributo di annotazione per un accesso più rapido (caricato all'avvio), anche se la protezione corrispondente non è altrettanto efficace.
Kotlin:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
fun callApi() {
api.connect("YOUR_API_KEY")
}
Java:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
public static void callApi() {
api.connect("YOUR_API_KEY");
}
Per utilizzarlo, aggiungi l'attributo dell'interfaccia al corpo della definizione dell'annotazione originale del passaggio 1:
// Aggiornamento definizione dell'annotazione di Kotlin
public annotation class PlayAutomaticIntegrityProtection(
/**
* Se impostato su true, il metodo annotato verrà caricato all'avvio. Se è impostato su false, verrà
* caricato on demand.
*
* <p>Per il caricamento on demand, la chiamata del metodo comporterà un calo delle
* prestazioni. Per il caricamento all'avvio, il metodo rimarrà deoffuscato in memoria
* per l'intero ciclo di vita dell'app.
*/
val loadAtStartup: Boolean = false
) {}
Passaggio 5: testa l'app
Best practice per la selezione dei metodi
Una selezione ponderata dei metodi favorisce una protezione complessiva più efficace. Se ogni nuova release include un metodo protetto di recente, quella versione dell'app o del gioco sarà più resiliente agli attacchi.
Come regola generale per evitare di influire sulle prestazioni dell'app, seleziona metodi a freddo anziché a caldo. Per la massima protezione, seleziona metodi con le seguenti caratteristiche:
- Sono essenziali per l'applicazione (l'app non funzionerebbe se venissero rimossi).
- Non vengono eseguiti nel thread dell'interfaccia utente/principale.
- Vengono eseguiti più di una volta durante il ciclo di vita dell'app, ma non in un loop a caldo.
- Non sono basilari (ovvero contengono codice o dati non basilari).
- Non vengono eseguiti durante l'avvio, se possibile.
- Sono stati introdotti di recente o sono stati rifattorizzati in modo significativo nella release.
- Non sono metodi astratti, metodi di interfaccia o costruttori.
- Non utilizzano la riflessione e non caricano direttamente una libreria nativa.
Rimuovi la protezione personalizzata
Se non vuoi più proteggere un metodo specifico, puoi semplicemente rimuovere l'annotazione @PlayAutomaticIntegrityProtection().