5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

グレンジAdvent Calendar 2024

Day 13

Play Integrity API サーバ側(PHP)のトークン復号サンプル

Last updated at Posted at 2024-12-12

グレンジ Advent Calendar 2024 13日目の記事を担当しました、k_kimura_01 と申します。
グレンジでサーバサイドエンジニアをしております。

Play Integrity APIとは

ざっくりいうと、Androidユーザに対して、正しいアプリ、アカウント、端末でプレイしているかどうかを検証することができるAPIになります。

詳しくは公式ドキュメントをご参照ください。

Play Integrity API の概要

今回やること

Play Integrity APIを利用してクライアント(Android)側で取得したトークンをサーバ側(PHP)で受け取った後の、「トークンを復号して結果を取得する」部分のサンプルになります。
また、2024年12月現在、Play Integrity APIは標準APIリクエストとクラシックAPIリクエストがありますが、今回は標準APIリクエストを想定しています。

下準備

GoogleのAPIを利用する共通の部分については基本的に省略させてもらいますが、ざっくり以下を事前に準備しておきます。

  • サービスアカウントの秘密鍵(jsonファイル)
  • google/apiclient 2.0.0以上
  • google/apiclient-services 0.282.0以上
    ※google/apiclient-servicesはこれより古いと標準APIリクエストで使用するRequestHashのパラメータが取得できないかも

実践

<?php

class MyPlayIntegrity
{
    private $client;

    /**
     * コンストラクタ
     */
    public function __construct()
    {
        $this->client = new \Google_Client();
        $this->client->setAuthConfig('private_key.json'); // サービスアカウントの秘密鍵のパス
        $this->client->addScope(\Google_Service_PlayIntegrity::PLAYINTEGRITY);
    }

    /**
     * 検証
     */
    public function verify($token)
    {
        // トークンを復号
        $decodeToken = $this->decodeToken($token);

        if (!is_null($decodeToken)) {
            $tokenPayload = $decodeToken->getTokenPayloadExternal();

            // 判定結果を取得
            // requestDetails
            $requestDetails = $tokenPayload->getRequestDetails();
            // パッケージ名
            $requestPackageName = $requestDetails->getRequestPackageName();
            // リクエストハッシュ
            $requestHash = $requestDetails->getRequestHash();
            // トークンの有効期限
            $timestampMillis = $requestDetails->getTimestampMillis();

            // appIntegrity->appRecognitionVerdict
            $appRecognitionVerdict = $tokenPayload->appIntegrity->appRecognitionVerdict;

            // deviceIntegrity->deviceRecognitionVerdict
            // ※通常は配列だが検証結果によっては空の値が返却されることがある
            $deviceRecognitionVerdict = $tokenPayload->deviceIntegrity->deviceRecognitionVerdict;

            // accountDetails->appLicensingVerdict
            $appLicensingVerdict = $tokenPayload->accountDetails->appLicensingVerdict;
        }
    }

    /**
     * トークンを復号
     */
    private function decodeToken($token)
    {
        $playIntegrityService = new \Google_Service_PlayIntegrity($this->client);

        $requestBody = new \Google_Service_PlayIntegrity_DecodeIntegrityTokenRequest([
            'integrityToken' => $token,
        ]);

        $decodeToken = null;
        try {
            // 復号
            $decodeToken = $playIntegrityService->v1->decodeIntegrityToken('アプリのパッケージ名を入れる', $requestBody);
        } catch (\Exception $e) {
            // 復号で失敗した時の処理など
        }

        return $decodeToken;
    }
}

エラー処理など諸々端折ってますが、これで取得できた情報を元に以下公式ドキュメントの各項目の値と見比べて検証をしていく感じになると思います。

完全性判定の結果

補足

トークンの復号について、標準APIリクエストではこの方法しか記載がないですがGoogleサーバでの復号になる為、1日のPlay Integrity APIリクエスト回数に含まれるようなので注意。
※デフォルトでは1日あたり10000件となっている

1 日あたりの Play Integrity API リクエスト数を引き上げる

終わりに

Play Integrity APIのトークン復号方法の例が思いのほか見つからなかったので記事にしてみました。
誰かしらの参考になれば幸いです。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?