i Cubed Systems Engineering blog

株式会社アイキューブドシステムズの製品開発メンバーが、日頃のCLOMO開発の様子などを紹介します。

Play Integrity APIへの移行

はじめに

アイキューブドシステムズで製品開発運用本部の製品開発部に所属している kazuya-oota です。 Google から提供されているSafetyNet Attestation APIの廃止により、CLOMOが提供するAndroid向けの機能の一つが将来的に利用不可となることがわかりました。 SafetyNet Attestation APIには後継となるPlay Integrity APIがリリースされています。今回の記事はこのSafetyNet Attestation API からPlay Integrity APIの移行についてご紹介します。

SafetyNet Attestation APIって何?

SafetyNet Attestation API は Googleから無料で提供されているAPIです。このAPIはアプリが動作しているAndroid デバイスをアプリの開発者が評価することができ、チートやアプリの改ざんといった不正利用の防止に利用します。 これは単純なルート化をチェックする機能ではありません。複数の情報からデバイスの完全性を判断するものです。

このフローは以下のようになっています。

  1. サーバーまたはアプリでNonce1を生成して、アプリはSafetyNet Attestation API を呼び出す。
  2. SafetyNet Attestation サービスは、アプリの実行環境を評価し、Google のサーバーに評価結果をリクエストする。
  3. Google のサーバーは、評価結果を SafetyNet Attestation サービスに送信する。
  4. アプリはSafetyNet Attestation サービスからの検証情報2を取得する。
  5. アプリはサーバーにSafetyNet Attestation APIの検証情報(とNonce)を送信する。
  6. サーバーは受信した検証情報を解析して不正判断をする。また、その検証結果をアプリに送信する。 この1.のAPI呼び出しには、Google Cloud Projectから発行されたAPIキーが必要になります。 詳しい手順はAPI キーを取得するにあります。 ・・・ですが、既に(2023年1月以降)新規開発者の登録は終了しています。

SafetyNet Attestation APIの検証情報は以下のようなJSON形式のデータです。 これらの具体的な内容はSafetyNet Attestation APIの検証情報で説明されています。

{
      "timestampMs": 9860437986543,
      "nonce": "R2Rra24fVm5xa2Mg",
      "apkPackageName": "com.package.name.of.requesting.app",
      "apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the
                                      certificate used to sign requesting app"],
      "ctsProfileMatch": true,
      "basicIntegrity": true,
}

また、SafetyNet Attestation はサポート終了が発表されており、ロードマップは以下のようになっています。 サポートの終了についての詳細はDiscontinuing the SafetyNet Attestation APIで説明されています。

年月日 内容
2022年6月 SafetyNetAttestation API 終了が発表。
2022年11月 deprecationInformation フィールド追加
開発者向けの非推奨の情報が含まれます。
2023年1月 新規登録終了
2023年1月31日以降、新規開発者の登録が終了。
2023年6月 移行期限
本番アプリがPlay Integrity APIに移行している場合は、引き続きSafetyNet Attestation APIは利用可能。
2024年6月 SafetyNet Attestation APIはすべてのバージョンのアプリで利用不可。

Play Integrity APIへの移行

先に述べたSafetyNet Attestation API は Play Integrity APIに統合されました。 Play Integrity APIでは3つの項目を検証をすることができます。

  • 正規のアプリ
    • Google Play にアップロードされた改変されていないアプリかどうかを判断します。
  • 正規の Play インストール
    • 現在のユーザー アカウントにライセンスが付与されているかどうか(つまりユーザーが Google Play でアプリまたはゲームのインストールや支払いを行ったかどうか)を判断します。
  • 正規の Android デバイス
    • Google Play 開発者サービスを搭載した正規の Android デバイスかどうかを示します。

SafetyNet Attestation APIを利用している場合は、Play Integrity APIへの移行は簡単です。 これはPlay Integrity APIを使用するアプリがGoogle Playで公開されたパブリックなアプリか、公開されていないプライベートなアプリかで有効化する方法が異なります。

Play Integrity API のフローはSafetyNet Attestation APIからほとんど変わりはありません。

  1. サーバーまたはアプリでNonceを生成して、アプリはPlay Integrity API を呼び出す。
  2. アプリはPlay Integrity APIから検証情報(token)3を取得する。
  3. アプリはサーバーにPlay Integrity APIの検証情報(とNonce)を送信する。
  4. サーバーはGoogle Playサーバーまたは自身のサーバーで検証情報を復号する。
  5. サーバーは受信した検証情報を解析して不正判断をする。また、その検証結果をアプリに送信する。

Play Integrity APIでは検証情報が暗号化される変更がありました。 サーバーはこれを復号する必要があり、これには2つの方法が提供されています。

  • 自前のサーバーで復号する方法
  • Google サーバーに復号を任せる方法(Googleの推奨方法)

自前のサーバーで復号する方法を使用する場合にはGoogle Playでアプリが公開されていることが条件です。どちらを選ぶかはサービスに依存すると思いますが、両方を試してから決定するとよいでしょう。

復号した検証情報は、ペイロードと呼ぶJSON形式のデータが含まれます。 これらは返されるペイロードの形式に詳細が解説されています。

{
  requestDetails: { ... }
  appIntegrity: { ... }
  deviceIntegrity: { ... }
  accountDetails: { ... }
}

それぞれのフィールドには以下のような情報が含まれます。

  • requestDetailsはAPIのリクエストに指定した情報が含まれます。
  • appIntegrityはパッケージに関する情報が含まれます。
  • deviceIntegrityはデバイスがアプリの完全性の強度が含まれます。
  • accountDetailsはアプリのライセンスまたは利用資格のステータスが含まれます。

検証情報のマッピング

SafetyNet Attestation APIとPlay Integrity APIの検証情報に含まれるJSONデータの構造は全て異なります。 そのため、SafetyNet Attestation APIの検証情報とPlay Integrity APIの検証情報の対比にはそれぞれに対応するパラメータが何かを明確にしてマッピングする必要があります。

これはAPI レスポンスのマッピングに詳しく解説されています。

例えば、SafetyNet Attestation APIで判断できた最も強度の高いデバイスのペイロードは以下のようになります。

  • ctsProfileMatch = true
  • basicIntegrity = true
  • evaluationType に HARDWARE_BACKEDを含む

これをPlay Integrity APIで同じ判断をするには以下のようになります。

  • deviceIntegrityに MEETS_STRONG_INTEGRITY, MEETS_DEVICE_INTEGRITY,MEETS_BASIC_INTEGRITYを含む

これらのマッピングはすべて表に載っているため、サービスの実装に合わせた改修を行うこととなります。

デバイスの完全性判定は、Google PlayからPlay Integrity APIを有効化している場合に追加のオプションが設定できます。SafetyNet Attestation APIの実装と完全に合わせるにはこれが必要な場合があり、先程の例に挙げたマッピングを行うためにはGoogle Play Consoleから設定する必要があります。

オプションの説明は以下の通りになります。

  • MEETS_STRONG_INTEGRITY
    • MEETS_DEVICE_INTEGRITYに加えてKey Attestation(鍵構成証明)を利用する。
  • MEETS_BASIC_INTEGRITY
    • 基本的なシステム完全性チェックに合格したデバイスで動作しているがAndroid の互換性要件を満たしておらず、Google Play 開発者サービスの実行を承認されていない可能性がある。

移行にあたって

Play Integrity APIへの移行にあたって、発生したトラブルなどを紹介します。

互換性要件を満たしたデバイスでペイロードがおかしい問題

  • 事象 Pixel 5a(Android 11)で確認時に、異常なペイロードがPlay Integrity APIから取得できてしまう。 デバイス完全性(deviceRecognitionVerdict)が空、アプリ情報(appIntegrity)にpackageNameやその他も無く、評価するためのペイロードが十分ではない。 デバイス側はPlay Integrity APIのAPIの呼び出しでエラーなどは発生していない。
  • 解決 Google Play 開発者サービス、Google Playのアップデートを実施で解決。Play Integrity APIにはこれらのパッケージが影響することがわかった。

個人利用のデバイスで定期的にアプリなどをアップデートしている場合は発生しないが、デバイスのファクトリーリセット直後などでGMSに関連するパッケージが更新されていないと問題が発生することがわかりました。 ただし、これはデバイスに依存するようでPixel 6(Android 13)などでは発生しませんでした。

バージョンの古いアプリとの共存

Androidやモバイルの宿命ではありますが、デバイスごとにアプリのバージョンが異なるという問題が発生します。 すべてのユーザーに常に最新バージョンのアプリを利用してもらうことは難しく、インストールされたAndroidデバイスごとにバージョンが異なるといったことが起きます。

この問題を解決するための方法としては、アプリ自身にバージョンチェック機能をもたせます。

  • アプリ起動時に外部サーバーと通信してバージョンチェックをする。
  • バージョンチェックに失敗すると起動フローを中止し、ユーザーに更新を促す。
  • バージョンチェックに成功すると起動する。

この機能は全てのアプリで機能するとは限りません。なぜなら、これらはアプリを利用するにはユーザーが明示的に起動する必要があるためです。

バージョンチェック機能を持たない、初期設定後はバックグラウンドで動作する、SafetyNet Attestation APIの検証が必須機能ではない、などの場合にはアプリのアップデートを強制することができません。 今回対応を行ったアプリはこちらにあたるため、SafetyNet Attestation APIとPlay Integrity APIの共存が必要になりました。

アプリの特性にもよりますが、可能な限りアプリはアップデートを強制することがよいでしょう。それが難しい場合にはSafetyNet Attestation APIが完全に終了する2024年6月までにユーザーにアップデートをしてもらえるよう適切にアナウンスする必要があります。

最後に

Googleのシステムの進化により、APIが統合されたことでこの対応を行いました。 単純な切り替えができると考えていましたが、実際に動かすことで見つかる課題も多くありました。

当社では、システム開発を通じて、問題を自らで調べ、考え、周りと協調して解決できる人材を募集しています。 カジュアル面談・エントリーは以下で随時受け付けています。


  1. 検証ごとに生成する一意の値。(詳細)
  2. JWSで表現されるデータであり、暗号化されていない。
  3. JWEで表現されるデータで、暗号化されている。