設備證明 Level 2:Google Play Integrity API(平台替你判定)

Chance Lu · 學習文章 · 2026-10-22 15:32
Chance Lu

L0 的骨架是:平台在保險箱裡蓋章,伺服器端負責驗章。L0 也預告過:Google 有一種請求方式由平台自動防重送,你只要把這次請求的內容綁進去。這一站就把那句話對上具體名詞,看 Android 上的 Play Integrity API 怎麼跑。

這站學完,你要能用自己的話回答:
① standard 請求和 classic 請求各在什麼時候用?各自怎麼防重送?
② 判定結果分成哪幾類?每一類在問什麼?
③ 伺服器拿到判定結果後,除了「放行/拒絕」還能怎麼回應?
④ 跟 Apple App Attest 比,Google 最大的不同在哪?

先認得這站的新名詞

名詞白話
Play Integrity APIGoogle 的設備證明服務。回答「這是從 Google Play 裝的正版 App、跑在真的認證 Android 裝置上嗎?」
Google Play 元件手機上 Google 提供的系統程式:Google Play Store 與 Google Play services 的合稱。它屬於平台,不是你的 App。
integrity tokenApp 向 Google Play 元件要到的一段加密又簽過章的資料。App 看不懂內容,只負責轉交。
verdict(判定結果)token 解密後的內容:一份 JSON,寫著平台已經判斷好的結論,例如「App 被 Google Play 認得」。
standard 請求大多數情況用的請求方式:事先準備,之後每次要 token 都很快(平均幾百毫秒)。
classic 請求原本的請求方式:每次都重新評估,比較慢(平均幾秒),只留給少數最重要的操作。
requestHashstandard 請求用的欄位:把這次請求內容做成的雜湊,交給 Play Integrity,之後原封不動出現在判定結果裡。
Play ConsoleGoogle Play 給開發者的管理後台:設定 App、開啟選用的判定項目、申請提高配額都在這裡。
service account給伺服器用的 Google 帳號,讓你的伺服器有權限呼叫 Google 的 API(例如請 Google 解密 token)。

角色對應:L0 的「平台」在這裡=Google Play 元件(在手機上)+安全硬體+Google 伺服器。

比喻延續「章」:Apple 是「開印鑑證明給你,伺服器自己存樣本、自己驗章」;Google 則像把蓋好章的密封信封交給你(信封=加密,章=簽章),你拿去 Google 的驗件窗口拆封,窗口直接告訴你結論。

Play Integrity 是什麼

兩種請求方式,判定結果的格式一樣:

standard 請求classic 請求
適合任何 App,隨時檢查任何操作偶爾一次,檢查最有價值、最敏感的操作
速度平均幾百毫秒(要先準備,約幾秒)平均幾秒
防竄改用 requestHash 綁請求內容用 nonce 綁請求內容
防重送Google Play 自動處理你自己用 nonce 加伺服器邏輯處理

註:最低 Android 版本以 Overview 頁和 classic 頁的比較表為準,現行 library 兩種都是 Android 6.0 以上;standard、classic 頁首寫的 5.0/4.4 是 v1.3.0 以前的數字。

一句話:Play Integrity 是 Google 版的設備證明;大多數情況用 standard 請求,classic 只留給少數關鍵操作。

standard 請求:流程

分兩段:事先準備,之後每次需要時要一個 token。

手機 你的 App發請求的人 Google Play 元件屬於平台 你的伺服器轉交、做決定 Google 伺服器解密、驗證 ⓪ 準備 準備會連到 Google 伺服器(約幾秒,事先做) ① 算 requestHash請求內容做雜湊 ② request() token ③ token+原本的請求 ④ decodeIntegrityToken ⑤ 判定結果(JSON) ⑥ 比對、判斷requestHash 對不對判定結果夠不夠好 ⑦ 決定(放行/限制/拒絕…)

圖 A:standard 請求。Google Play 元件背後用到安全硬體的訊號,但那屬於平台,不在你的 App 裡(點圖可放大)

事先準備(prepare/warm up)

每次需要時:綁 requestHash、拿 token

  1. 算 requestHash:把這次操作的所有相關參數,用固定的方式排好再做雜湊(例如 SHA256)。最長 500 bytes。
  2. 要 token:用 StandardIntegrityTokenRequest 的 setRequestHash 帶入,呼叫 token provider 的 request()。
  3. 送到你的伺服器:把 token 和原本的請求一起送出。
  4. 交給 Google 解密:你的伺服器用 service account 取得存取權,呼叫 decodeIntegrityToken,拿回判定結果。
// Request integrity token by providing a user action request hash.
String requestHash = "2cp24z...";
Task<StandardIntegrityToken> integrityTokenResponse =
    integrityTokenProvider.request(
        StandardIntegrityTokenRequest.builder()
            .setRequestHash(requestHash)
            .build());

(程式碼摘自 Android Developers 官方文件。)

requestHash 要綁什麼、怎麼驗

Google 怎麼替你防重送

standard 請求自動防重送:Google Play 會阻止同一個 token 被重複使用很多次。同一個 token 被重複解密時,判定結果會被清空:

Google 擋的是大量重複使用,timestampMillis 還是要你自己檢查。對回 L0 的三項檢查,standard 下是這樣分工:

一句話:standard 請求=事先準備 → 每次把請求內容綁進 requestHash 拿 token → 你的伺服器交給 Google 解密;「用過沒」由 Google 處理,「對不對」和「過期沒」你自己查。

classic 請求:只留給少數關鍵操作

nonce 由誰產生、怎麼防重送

名詞提醒:三個長得像的東西
・L0 的 challenge:伺服器發的一次性亂數,泛稱。
・classic 的 nonce:你交給 Play Integrity 的欄位值,內容是唯一值,或「唯一值+訊息」的雜湊;會原封不動出現在判定結果裡。
・L1 Apple 的 nonce:你的伺服器用 authData 和 clientDataHash 算出來比對用的值,不是你送出去的。

token 解密的兩種方式

  1. 交給 Google 伺服器解密(官方建議):跟 standard 一樣,呼叫 decodeIntegrityToken。
  2. 自己解:classic 可以選擇自己保管 Play Console 給的金鑰,在自己的伺服器解密、驗章;standard 只能交給 Google 解。
一句話:classic=你自己產生唯一的 nonce、自己記錄防重送;token 可交給 Google 解,也可自己解。

判定結果:五類,各自在問什麼

不管 standard 或 classic,判定結果都是同一種格式的 JSON。官方要求先驗 requestDetails,再看其他類別。

判定結果解密後的 JSON requestDetails(先驗這個)這是我的 App、這次的請求嗎?時間夠新嗎? appIntegrity是 Google Play 認得、沒被改過的那個 App 嗎? deviceIntegrity這台裝置可信嗎?可信到哪一級? accountDetails使用者是從 Google Play 取得這個 App 的嗎? environmentDetails(選用)旁邊有沒有可疑的 App?Play Protect 有沒有開、有沒有發現問題?

圖 B:判定結果的五個類別(點圖可放大)

  1. requestDetails:這是我這次的請求嗎?套件名稱要是你的 App,requestHash(classic 是 nonce)要對上,timestampMillis 要夠新。
  2. appIntegrity:是那個沒被改過的 App 嗎?看 App 和它的簽章憑證是否符合 Google Play 發行的版本。
  3. deviceIntegrity:裝置可信嗎?回傳一個或多個等級標籤;一個都不符合,就沒有標籤。
  4. accountDetails:使用者是從 Google Play 取得的嗎?看這個帳號有沒有這個 App 的 Play 授權。
  5. environmentDetails(選用):執行環境有沒有風險?要在 Play Console 開啟才會出現。
各類別的欄位與標籤(實作時看)
一句話:先確認 requestDetails(是這次的請求),再看 App、裝置、帳號、環境各自可不可信。

拿到判定結果後怎麼決定

先過基本檢查,再分級

  1. 基本檢查:requestDetails 對上;appRecognitionVerdict 是 PLAY_RECOGNIZED;appLicensingVerdict 是 LICENSED。
  2. 依裝置可信度分級。先知道兩件事:一台裝置會拿到它符合的所有標籤,而除了預設標籤,其他標籤要先在 Play Console 開啟;同一個標籤在 Android 13 前後標準不同。從高到低:
    • MEETS_STRONG_INTEGRITY(Android 13 以上):最高級,要硬體訊號加上近期安全更新。
    • MEETS_DEVICE_INTEGRITY(Android 13 以上)與 MEETS_STRONG_INTEGRITY(Android 13 以前):都靠硬體訊號。
    • MEETS_DEVICE_INTEGRITY(Android 13 以前):有硬體就用硬體證明,沒有就退回軟體證明。
    • MEETS_BASIC_INTEGRITY:最弱的一級,再下去就是沒有任何標籤。
  3. 再疊其他訊號:例如 recentDeviceActivity 等級高的裝置,信任度就調低。

Android 13 前後差在哪:Android 13 以上,MEETS_DEVICE_INTEGRITY 要有硬體證明開機程式鎖定、系統是原廠認證映像;MEETS_STRONG_INTEGRITY 還要裝置所有分割區在一年內有安全更新。Android 12 以下的 MEETS_STRONG_INTEGRITY 只要求硬體證明開機完整性、不要求近期更新,所以要搭配 deviceAttributes 的 sdkVersion 一起判斷。

官方提醒:越高等級的裝置越少,只認最高等級會擋掉很多人,所以建議分級處理。

回應不只放行和拒絕

(兩個平台共用的處理策略見 L3。)

補救流程:判定有問題時,App 可以用 showDialog 跳出 Google Play 的對話框請使用者自己修,例如 GET_LICENSED 引導到 Google Play 取得正版;要跳哪一種,由伺服器看完判定結果後決定。關掉對話框後再要一次 token 確認(standard 要重新準備)。

一句話:先過三項基本檢查,再依裝置等級分級回應;有問題時可以請使用者自己補救。

跟 L1 的 Apple App Attest 對照

Apple App AttestGoogle Play Integrity
誰驗你的伺服器自己驗憑證鏈、nonce、欄位Google 伺服器解密驗證,你拿回結果(classic 也可自己解)
要一次性註冊嗎要:attestation,伺服器存公鑰不用伺服器端註冊(不必存公鑰)。standard 要由 App 事先準備,這步會連 Google 伺服器,但你的伺服器不參與
怎麼防重送你發 challenge,加上 counter 遞增standard:Google 擋重複使用,你綁 requestHash、檢查時間戳
classic:你自己用 nonce 並記錄
伺服器拿到什麼平台簽過的證明原料(註冊時是 Apple 開的憑證,之後是裝置金鑰蓋的章),結論自己算平台已經判斷好的判定結果(JSON)

兩邊差這麼多,伺服器要怎麼用同一套邏輯處理,是 L3 的主題。

常見的坑

一句話:配額要申請、結果別快取、時間戳要檢查、Android 13 前後標準不同、沒有 Google Play 元件就拿不到。

✔ 過關標準

能不看筆記回答下面 5 題,這站就過了。

  1. standard 和 classic 請求各在什麼時候用?看答案收合
    standard:大多數情況,隨時檢查任何操作,事先準備、之後很快。classic:偶爾一次,只給最有價值或最敏感的操作,比較慢也比較耗資源。
  2. 兩種請求各自怎麼防重送?看答案收合
    standard:Google Play 擋同一個 token 被大量重複使用(重複解密會清空結果);你負責比對 requestHash、檢查 timestampMillis。classic:你自己產生唯一的 nonce,伺服器記錄用過的值,重複或沒發過的就拒絕。
  3. 判定結果有哪五類?為什麼要先看 requestDetails?看答案收合
    requestDetails、appIntegrity、deviceIntegrity、accountDetails、environmentDetails(選用)。先看 requestDetails,是要確認這份結果真的是為你這次的請求產生的,其他類別才有意義。
  4. 伺服器除了放行和拒絕,還能怎麼回應?看答案收合
    依裝置等級分級:例如 Allow、Allow with limits、Allow with limits after CAPTCHA completion、Deny;也可以由伺服器決定,請 App 跳出 Google Play 的補救對話框讓使用者自己修。
  5. 跟 Apple App Attest 比,最大的不同是什麼?看答案收合
    Apple 要伺服器端的一次性註冊、你的伺服器自己驗證明、自己防重送;Google(standard)不用伺服器端註冊、由 Google 伺服器解密並擋重複使用,你拿到的是已經判斷好的結果。

下一站

Level 3 會回到伺服器端,看怎麼用同一套邏輯同時接住 Apple 和 Google 兩邊,以及驗證失敗時怎麼降級。

參考來源