この記事では、お客様のアプリやゲームで Google Play の改ざん対策をカスタマイズする方法について説明します。このページで説明するカスタマイズ機能を使用するには、Google Play Console で改ざん対策をオンにした自動保護を使用する必要があります。
改ざん対策のカスタマイズについて
改ざん対策機能のカスタマイズにより、お客様のアプリ内で、さらに強力なセキュリティが必要な Java メソッドと Kotlin メソッドを特定できます。リリースを Google Play にアップロードすると、Google Play がこれらの特定のメソッドの保護を優先して強化します。
保護を強化するメソッドを特定することで、改ざんに対するアプリの保護をさらに強化できます。メソッドを保護すると、クライアント シークレット(クライアントに含める必要がある機密性の高いキーや URL など)がバイナリから漏洩するのを防ぐこともできます。
カスタマイズされた改ざん対策をセットアップする
カスタマイズされた改ざん対策をアプリのコードベースに実装する手順は次のとおりです。
ステップ 1: 自動保護インターフェースをコードベースに追加する
まず、保護インターフェースをアプリまたはゲームに追加します。
Kotlin:
package com.google.android.play.protections.annotations/**
* メソッドが保護強化の候補であることを示します。
*
* <p>このアノテーションは、Google Play がバンドルを保護する際に、
* バンドルの dex コードから自動的に削除されます。
* メソッドレベルのアノテーションとしてのみ使用します。その他の使用方法
* (実行時にクラスにリフレクションでアクセスするなど)はサポートされていません。
*/
@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;
/**
* メソッドが保護強化の候補であることを示します。
*
* <p>このアノテーションは、Google Play がバンドルを保護する際に、
* バンドルの dex コードから自動的に削除されます。
* メソッドレベルのアノテーションとしてのみ使用します。その他の使用方法
* (実行時にクラスにリフレクションでアクセスするなど)はサポートされていません。
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PlayAutomaticIntegrityProtection {}
# アノテーション クラスとそのメンバーを保持します。
-keep class com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection* { *; }
# デフォルトでは、ProGuard はアノテーション属性を省略可として扱い、
# 難読化ステップで削除します。以下のルールにより、これを削除されないようにします。
-keepattributes RuntimeVisibleAnnotations, AnnotationDefault
# このアノテーション付きメソッドを保持しますが、難読化は許可します。
-keepclassmembers,allowobfuscation class * {
@com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection *;
}
ステップ 2: カスタム保護用にメソッドにアノテーションを付ける
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection
@PlayAutomaticIntegrityProtection()
fun myMethod() {
// メソッドの本体...
}
Java
import com.google.android.play.protections.annotations.PlayAutomaticIntegrityProtection;
@PlayAutomaticIntegrityProtection()
public void myMethod() {
// メソッドの本体...
}ステップ 3:(省略可)クライアントサイドのシークレットを保護する
メソッドのカスタム保護機能は、アノテーション付きメソッドの本体内でコードを直接難読化(非表示化)します。この機能を使用することで、機密性の高い API キーを保護できます。
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");
}
ステップ 4: (省略可)保護によるパフォーマンス オーバーヘッドを管理する
デフォルトでは、保護されたメソッドを呼び出すと、数ミリ秒のオーバーヘッドがかかります。そのため、パフォーマンスが重要な場合やメインスレッドでは呼び出さないでください。
高速実行が必要なメソッドを保護する必要がある場合は、これより軽量な保護モードを使用できます。アノテーション属性を使用して高速アクセス(起動時に読み込まれます)を選択できます。ただし、これに対応する保護はそれほど強力ではありません。
Kotlin:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
fun callApi() {
api.connect("YOUR_API_KEY")
}
Java:
@PlayAutomaticIntegrityProtection(loadAtStartup = true)
public static void callApi() {
api.connect("YOUR_API_KEY");
}
これを使用するには、ステップ 1 の最初のアノテーション定義の本体にインターフェース属性を追加します。
// Kotlin アノテーション定義の更新
public annotation class PlayAutomaticIntegrityProtection(
/**
* true の場合、アノテーション付きメソッドは起動時に読み込まれます。false の場合、
* オンデマンドで読み込まれます。
*
* <p>オンデマンド読み込みの場合、このメソッドを呼び出すとパフォーマンスが低下します。
* 起動時の読み込みの場合、このメソッドはアプリのライフサイクル全体にわたってメモリ内で
* 難読化が解除されたままになります。
*/
val loadAtStartup: Boolean = false
) {}
ステップ 5: アプリをテストする
メソッドを選択する際のベスト プラクティス
メソッドを慎重に選択することは、全体的な保護の強化につながります。新たにリリースするたびに、メソッドを新たに保護すると、そのバージョンのアプリまたはゲームは攻撃に対する耐性が高くなります。
アプリのパフォーマンスへの影響を避けるための原則として、頻繁に実行されるメソッドではなく、あまり実行されないメソッドを選択するようにしてください。保護を最大限に高めるには、次の条件を満たすメソッドを選択します。
- アプリに不可欠である(削除するとアプリが機能しない)。
- メインスレッドまたは UI スレッドでは実行されない。
- アプリのライフサイクル中に複数回実行されるが、頻繁に実行されるループでは実行されない。
- 非自明なメソッド(非自明なコードまたはデータを含むメソッド)。
- できれば、起動中に実行されないメソッド。
- リリースで新たに導入されたメソッドや、大幅にリファクタリングされたメソッド。
- 抽象メソッド、インターフェース メソッド、コンストラクタではない。
- リフレクションを使用せず、ネイティブ ライブラリを直接読み込まない。
カスタマイズされた保護を削除する
特定のメソッドを保護する必要がなくなった場合は、@PlayAutomaticIntegrityProtection() アノテーションを削除するだけです。