Androidアプリのセキュリティ対策として、GoogleはPlay Integrity APIという機能を提供しています。
このAPIでは、アプリがGoogle Playに認識されている正規のものか、実行環境が信頼できる端末なのか、といった情報を取得できます。
ただし、取得した判定結果をAndroidアプリ側で確認するだけでは十分ではありません。
完全性トークンをバックエンドで検証し、その結果をどのように利用するかまで設計する必要があります。
また、Google PlayにはAutomatic protection(自動保護)という関連機能も用意されていますが、Play Integrity APIとは役割が異なります。
今回はPlay Integrity APIで取得できる判定情報から、完全性検証の仕組み、導入時の注意点まで、Googleの公式ドキュメントをもとに整理してみます。
※2026年10月時点の公式仕様をもとにした解説です。
実際のアプリに対する攻撃や耐改ざん性能の検証は行っていません。
Play Integrity APIとは?
Play Integrity APIは、Google Playが提供するアプリや端末の完全性に関する判定情報を取得するためのAPIです。
AndroidアプリはAPKとして配布されますが、APKの内部構造を解析し、コードやリソースに変更を加えることは技術的に可能です。
Androidにはアプリ署名の仕組みがあるため、異なる鍵で署名されたAPKを正規アプリのアップデートとしてそのままインストールすることは通常できませんが、改変されたAPKが別の経路から配布される可能性はあります。
こうした状況で問題になるのが、アプリや端末の信頼性をどのように確認するかという点です。
例えば、アプリから送信されたパッケージ名やバージョン番号だけでは、正規のアプリから送られた情報であることを証明できません。
そのため、Google Playが提供する完全性の判定情報を利用し、信頼性を確認する仕組みが用意されています。
ただし、Play Integrity APIは改ざん自体を直接防止するものではなく、信頼性を判断するための情報を提供するAPIです。
この違いについては、後ほどAutomatic protectionとの比較でも触れます。
Play Integrity APIで検証できること
Play Integrity APIで取得できる主な情報は、以下の4つです。
| フィールド | 内容 |
|---|---|
appIntegrity |
アプリがGoogle Playに認識されている正規のものか |
deviceIntegrity |
実行環境の信頼性がどの程度あるか |
accountDetails |
Google Play上でアプリの利用資格があるか |
requestDetails |
どのリクエストに対する判定なのか |
これらはそれぞれ異なる目的で利用する情報です。
例えば、アプリ自体が正規のものであっても、動作している端末の完全性が十分とは限りません。
それぞれの内容を確認していきます。
appIntegrity:アプリの完全性を確認する
appIntegrityでは、アプリがGoogle Playに認識されているバージョンかどうかを確認できます。
主な判定結果は以下のとおりです。
| 判定結果 | 内容 |
|---|---|
PLAY_RECOGNIZED |
アプリと署名証明書がGoogle Playの記録と一致する |
UNRECOGNIZED_VERSION |
アプリのパッケージや署名証明書がGoogle Playの記録と一致しない |
UNEVALUATED |
必要な条件を満たさず、評価できなかった |
例えば、Google Playから配信されている正規のアプリであれば、PLAY_RECOGNIZEDが返されることが期待されます。
一方、UNRECOGNIZED_VERSIONが返された場合でも、必ずしも悪意のある改ざんが行われたとは限りません。
Google Playに登録されていない開発用ビルドや、異なる署名証明書でビルドしたアプリなども該当する可能性があります。
また、UNEVALUATEDは完全性の評価ができなかった状態です。
これも改ざんされたことを直接示すものではありません。
実際の判定結果には、appRecognitionVerdictに加え、評価できた場合はパッケージ名や署名証明書のSHA-256ダイジェスト、バージョンコードなども含まれます。
そのため、単純に判定結果だけを見るのではなく、想定しているアプリの情報と一致しているかも確認することが重要です。
deviceIntegrity:端末の完全性を確認する
deviceIntegrityでは、アプリが動作している端末の信頼性を確認できます。
代表的な判定は以下のとおりです。
| 判定結果 | 内容 |
|---|---|
MEETS_BASIC_INTEGRITY |
基本的なシステム完全性の条件を満たしている |
MEETS_DEVICE_INTEGRITY |
正規の認定済みAndroid端末としての信頼性要件を満たしている |
MEETS_STRONG_INTEGRITY |
より強い完全性要件を満たしている |
なお、MEETS_BASIC_INTEGRITYとMEETS_STRONG_INTEGRITYは追加設定によって利用できる判定です。
標準で返されるMEETS_DEVICE_INTEGRITYとは扱いが異なるため注意が必要です。
また、これらは単純な3段階評価ではありません。
条件を満たしていれば複数のラベルが返されることがあり、いずれの条件も満たさない場合は判定ラベル自体が省略されることもあります。
特にMEETS_STRONG_INTEGRITYは、Androidのバージョンによって条件が異なります。
Android 13以降では、ハードウェアに基づく完全性に加え、OSやベンダー領域に最近のセキュリティアップデートが適用されていることも必要になります。
一方、Android 12以前では、同じラベルであっても最近のセキュリティアップデートまでは要求されません。
つまり、MEETS_STRONG_INTEGRITYという判定だけを見ても、Androidのバージョンによって保証される内容が異なります。
このため、端末の完全性を判断する際には、必要に応じてAndroidのバージョンも確認する必要があります。
accountDetails:Google Playの利用資格を確認する
accountDetailsでは、Google Play上でアプリの利用資格があるかを確認できます。
主な判定結果は以下のとおりです。
| 判定結果 | 内容 |
|---|---|
LICENSED |
Google Play上でアプリの利用資格が確認できる |
UNLICENSED |
Google Play上で利用資格が確認できない |
UNEVALUATED |
必要な条件を満たさず、評価できなかった |
例えば、Google Playからアプリをインストールまたは更新したユーザーであれば、LICENSEDが返されることが期待されます。
ただし、ここでいうライセンスは、アプリ独自のユーザー認証やサブスクリプションの契約状態とは別のものです。
あくまでGoogle Play上でアプリを取得・利用する資格に関する情報になります。
requestDetails:リクエストの整合性を確認する
requestDetailsには、完全性トークンを要求した際の情報が含まれます。
標準APIリクエストでは、主に以下の情報を確認できます。
| フィールド | 内容 |
|---|---|
requestPackageName |
トークンを要求したアプリのパッケージ名 |
requestHash |
リクエストに関連付けたハッシュ値 |
timestampMillis |
トークンを要求した時刻 |
これらは、取得した完全性判定が、期待しているリクエストに対応するものかを確認するために利用します。
例えば、完全性トークン自体が正しいものであっても、別のリクエストに対して取得されたものであれば、そのまま信頼するべきではありません。
そこでrequestHashを利用し、完全性トークンと実際のリクエスト内容を関連付けることができます。
この仕組みについては、後ほど詳しく説明します。
その他の判定情報
Play Integrity APIでは、追加設定によってさらに多くの情報を取得できます。
例えば、以下のようなものがあります。
| 判定情報 | 内容 |
|---|---|
appAccessRiskVerdict |
画面のキャプチャやオーバーレイ、端末操作などを行うアプリによるリスク |
playProtectVerdict |
Google Play Protectの状態や検出されたリスク |
recentDeviceActivity |
最近の完全性トークン要求の頻度 |
deviceRecall |
過去に記録した端末に関する情報を再利用する仕組み(ベータ) |
このように、Play Integrity APIは単純なAPK改ざん検知だけではなく、端末の実行環境や不正利用の兆候を確認する用途にも利用できます。
ただし、すべての判定情報が標準で返されるわけではなく、利用には追加設定や条件が必要なものもあります。
参考:完全性判定の詳細
完全性検証はどのように行われるのか?
Play Integrity APIでは、Androidアプリから完全性トークンを取得し、そのトークンをバックエンドで検証する構成が推奨されています。
基本的な流れは以下のとおりです。
Androidアプリ
│
│ ① 完全性トークンを要求
▼
Google Play
│
│ ② 完全性トークンを返却
▼
Androidアプリ
│
│ ③ トークンをバックエンドへ送信
▼
バックエンド
│
│ ④ Google Playへ復号・検証を要求
▼
Google Play
│
│ ⑤ 検証済みの判定情報を返却
▼
バックエンド
│
│ ⑥ 判定結果に応じて処理を制御
▼
Androidアプリ
まずAndroidアプリ側で完全性トークンを取得します。
取得したトークンは、そのままアプリのバックエンドへ送信します。
バックエンドはGoogle Playのサーバーへトークンを送信し、復号・検証された判定情報を受け取ります。
その結果をもとに、処理を許可するか、制限するかなどを判断する仕組みです。
ここで重要なのは、完全性トークンの取得と、その判定結果に基づく処理の制御が別の役割になっていることです。
Androidアプリはトークンの取得を担当し、バックエンドが判定結果を利用して処理を制御します。
標準APIとクラシックAPI
Play Integrity APIには、標準APIリクエストとクラシックAPIリクエストの2種類が用意されています。
| 項目 | 標準API | クラシックAPI |
|---|---|---|
| 主な用途 | 通常のアプリ操作やサーバーリクエストの検証 | 特に重要な処理の検証 |
| 応答速度 | 比較的速い | 標準APIより時間がかかる |
| 判定情報の取得 | デバイス上のキャッシュを活用 | 新しい評価を実行 |
| リクエストとの関連付け | requestHash |
nonce |
| リプレイ対策 | Google Playによる対策あり | 開発者側でも対応が必要 |
Googleは一般的な用途に標準APIを推奨しています。
標準APIでは、事前にStandardIntegrityTokenProviderを準備する処理があり、必要なタイミングで完全性トークンを要求できます。
この事前準備によって、一部の完全性情報がキャッシュされ、トークン取得時の遅延を抑える仕組みです。
一方、クラシックAPIは都度新しい評価を実施するため、標準APIよりも処理時間や端末への負荷が大きくなります。
そのため、特に重要な操作など、限定的な場面での利用が想定されています。
参考:標準APIリクエスト
なぜバックエンドでの検証が必要なのか?
ここまでの説明で気になるのが、なぜAndroidアプリだけで検証を完結させないのかという点です。
理由は、改ざんの可能性があるクライアント自身に、セキュリティ上の判断を任せるべきではないためです。
例えば、Androidアプリ内で完全性の判定を行い、その結果に応じて機能を制限する仕組みを実装したとします。
しかし、アプリ自体が改ざんの対象になることを考えると、判定結果を確認する処理も変更される可能性があります。
これでは、完全性の検証を導入しても、その結果を無視するように改変されるリスクが残ります。
一方、バックエンドで完全性トークンを検証し、サーバー側で処理を制御する構成であれば、クライアント側の判定処理を変更されても、サーバー側の制限を直接解除することはできません。
そのため、Play Integrity APIの判定結果を信頼できる環境で検証し、必要な処理の制御に結び付けることが重要になります。
なお、バックエンドは必ずしも大規模なサーバーである必要はありません。
サーバーレス関数などを利用することも可能です。
ただし、完全にオフラインで動作するアプリでは、サーバー側で処理を制御することができないため、Play Integrity APIだけで強制力のある保護を実現することは難しくなります。
requestHashによるリクエストの整合性確認
Play Integrity APIでは、完全性トークンが正規のものであれば、すべてのリクエストを無条件に信頼できるわけではありません。
例えば、ある操作に対して取得した完全性トークンを、別の操作に流用しようとするケースが考えられます。
このような問題への対策として、標準APIではrequestHashを利用できます。
requestHashの仕組み
requestHashは、完全性トークンを特定のリクエスト内容に関連付けるための値です。
例えば、次のような流れになります。
Androidアプリ
│
│ リクエストの重要なパラメータを
│ SHA-256などでハッシュ化
▼
requestHashを生成
│
▼
完全性トークンを取得
│
▼
バックエンドへ送信
│
▼
Google Playでトークンを検証
│
▼
requestHashを取り出す
│
▼
バックエンドでも同じ方法で
リクエストのハッシュを生成
│
▼
両者を比較
バックエンドでは、トークンに含まれるrequestHashと、実際のリクエスト内容から生成したハッシュを照合します。
これによって、完全性トークンが想定しているリクエストに対応しているか確認できます。
ただし、アプリ側とバックエンド側で同じハッシュを生成できるよう、対象データの形式を統一する必要があります。
例えば、JSONのフィールド順序などが異なると、論理的に同じ内容でも異なるハッシュになる可能性があります。
また、requestHashには機密情報を平文で含めないことが重要です。
なお、標準APIにはGoogle Playによるリプレイ攻撃対策が組み込まれていますが、requestHashはリクエスト内容との関連付けを担うものです。
両者は役割が異なるため、混同しないようにしたいところです。
バックエンドで確認する項目
実際に検証する際には、単純にappIntegrityだけを見るのではなく、複数の情報を組み合わせます。
例えば、以下のような項目です。
-
requestPackageNameが想定するパッケージ名と一致するか -
requestHashが実際のリクエスト内容と一致するか -
timestampMillisが許容する時間内か -
appRecognitionVerdictが期待する判定になっているか - 必要な
deviceIntegrityの条件を満たしているか
どの項目を必須とするかは、保護したい処理やアプリの利用環境によって異なります。
また、UNEVALUATEDやネットワークエラーなど、判定自体が取得できないケースも考慮する必要があります。
Play Integrity APIでできないこと
ここまでの内容から、Play Integrity APIはアプリや端末の信頼性を確認するうえで有用な仕組みであることが分かります。
ただし、いくつかの限界もあります。
まず、Play Integrity APIはAPKの解析や改変そのものを直接防止する機能ではありません。
改変されたアプリの実行や不正なリクエストを検出するための判定情報を提供するものです。
また、判定結果が正常であっても、アプリケーション内部のすべての処理が安全であることを保証するものではありません。
例えば、バックエンド側に適切な認可処理が存在しなければ、完全性の判定だけで不正な操作を防ぐことはできません。
そのためGoogleも、Play Integrity APIを単独のセキュリティ対策として利用するのではなく、他の対策と組み合わせることを推奨しています。
では、APKの改ざんや不正な再配布そのものへの対策はどうすればよいのでしょうか。
ここで関連するのが、Google PlayのAutomatic protectionです。
Automatic protectionとの違い
Automatic protection(自動保護)は、Google Playがアプリに保護機能を追加する仕組みです。
Play Integrity APIが信頼性の判定情報を提供するのに対し、Automatic protectionは不正な再配布や改ざんへの対策をアプリに追加することを目的としています。
また、バックエンドとの統合を必要とせず、Google Play Consoleから設定できる点も特徴です。
ただし、利用できる保護機能には違いがあります。
インストーラチェック
自動保護では、アプリにGoogle Playのインストーラチェックを追加できます。
このチェックはアプリの起動時に行われ、Google Play以外からアプリを取得した場合など、チェックに失敗したユーザーに対して、Google Playから正規のアプリを入手するよう求めるメッセージが表示されます。
主な目的は、不正な配布経路からアプリを取得したユーザーを、正規の配布経路へ誘導することです。
改ざん対策
一部のPlayパートナーには、ランタイムでの改ざん対策も提供されています。
この機能では、アプリの実行中に改変を検出するチェックや、リバースエンジニアリングを難しくする保護が追加されます。
チェックに失敗した場合、正規アプリの取得を促すメッセージが表示され、アプリの実行が停止されます。
ただし、この改ざん対策はすべての開発者が利用できるわけではありません。
Googleの公式ドキュメントでも、一部のPlayパートナーに提供が限定されていると案内されています。
また、改ざんを完全に防止できるわけではなく、攻撃に必要なコストや難易度を高めるための対策として位置付けられています。
自動保護の利用条件
Automatic protectionを利用する場合、主に以下の条件があります。
- Google Playアプリ署名を使用している
- Android App Bundle形式で公開している
- 最小APIレベルが24以上である
- Google Play Consoleで自動保護を有効にする
また、追加の改ざん対策やデバイスチェックを利用する場合には、別途条件が設けられています。
自動保護によってアプリの動作や起動時間に影響が出る可能性もあるため、Googleはテストトラックでの検証を推奨しています。
導入する際に注意したいこと
Play Integrity APIを導入する場合、APIを組み込んでトークンを取得するだけでは十分ではありません。
特に、次のような点は事前に整理しておきたいところです。
1. 何を保護したいのか
まず、保護対象を明確にする必要があります。
例えば、不正な環境からのサーバーリクエストを検出したいのか、不正な再配布を抑止したいのかによって、適切な対策は異なります。
前者であればPlay Integrity APIが候補になりますし、後者であればAutomatic protectionの利用も検討できます。
2. 判定結果をどう扱うのか
Play Integrity APIは判定情報を返しますが、その結果をどう利用するかは開発者側で設計する必要があります。
例えば、信頼性の低い環境からのすべてのリクエストを拒否する方法も考えられますが、それによって正規のユーザーまで利用できなくなる可能性があります。
Googleも、最初から厳しい制限を設けるのではなく、判定結果を収集して利用環境を把握し、段階的に対策を導入する方法を推奨しています。
3. バックエンドで適切に検証できるか
完全性トークンは、取得しただけでは意味がありません。
Google Playで復号・検証した判定結果をバックエンドで確認し、必要な処理制御に反映する必要があります。
また、requestHashやトークンの発行時刻などを確認し、想定していないリクエストに判定結果が利用されないようにすることも重要です。
4. 正常なユーザーへの影響
完全性の判定結果は、端末やAndroidのバージョン、Google Playの利用環境によって異なります。
そのため、特定の判定を満たしていないユーザーをすべて不正な利用者として扱うのは適切ではありません。
例えば、UNEVALUATEDのように評価できなかった場合や、一時的な通信エラーが発生した場合の動作も考慮する必要があります。
セキュリティを強化することは重要ですが、その結果として正常なユーザーが必要以上に制限されないようにすることも大切です。
まとめ
今回は、Play Integrity APIで取得できる判定情報と、完全性検証の仕組みについて整理しました。
Play Integrity APIでは、appIntegrityやdeviceIntegrityなどを利用し、アプリや端末の信頼性を確認できます。
ただし、判定結果をアプリ内で確認するだけでは十分ではなく、バックエンドで検証し、その結果を必要な処理の制御に利用することが重要です。
また、Play Integrity APIとAutomatic protectionは目的が異なります。
Play Integrity APIは信頼性に関する情報を提供する仕組みであり、Automatic protectionはGoogle Playがアプリに保護機能を追加する仕組みです。
そのため、どちらか一方ですべてのセキュリティ対策が完結するわけではありません。
個人的に重要だと感じたのは、完全性を検証することと、その結果によって何を制御するかは別の問題だという点です。
Play Integrity APIは、アプリや端末の信頼性を判断するための有用な情報を提供してくれます。
一方で、その情報をどこで検証し、どのように利用するかは、アプリケーション側で設計する必要があります。
導入を検討する際には、まず保護したい対象を明確にし、それぞれの機能の役割を理解したうえで適切な構成を考えるのがよさそうです。