# 第 4 篇:Google Play Integrity 深入解析 ## 前言:Android 平台的完整性驗證 在上一篇,我們了解了 reCAPTCHA 如何提供通用的人機識別。但是,reCAPTCHA 無法回答一個關鍵問題:**這個請求真的來自未被篡改的正版應用程式嗎?** Google Play Integrity 專門解決這個問題,提供 **Android 平台專屬的應用程式與裝置完整性驗證**。 ## Play Integrity 的核心價值 ### 為什麼需要 Play Integrity? ``` reCAPTCHA 無法防範的攻擊: ├── 反編譯應用程式 ├── 修改 APK 程式碼 ├── 在模擬器上執行 ├── 在 Root 裝置上繞過檢查 └── 使用破解工具修改應用行為 Play Integrity 可以偵測: ├── ✅ 應用程式是否來自 Play Store ├── ✅ 應用程式是否被篡改 ├── ✅ 執行環境是否為真實 Android 裝置 ├── ✅ 裝置是否通過 Google 認證 └── ✅ 裝置上是否有惡意軟體 ``` ### 與 reCAPTCHA 的差異 | 特徵 | reCAPTCHA | Play Integrity | |------|-----------|----------------| | 驗證對象 | 使用者行為 | 應用程式 + 裝置 | | 防護重點 | 機器人、腳本 | 破解、模擬器 | | 平台支援 | 跨平台 | 僅 Android | | 驗證深度 | 行為分析 | 硬體 + 軟體完整性 | | 依賴 | Google 服務 | Google Play Services | ## Play Integrity 核心概念 ### 五大驗證維度 Play Integrity 從五個維度全面驗證請求的可信度: #### 1. Request Details (請求詳情) ``` 驗證內容: ├── Request Package Name │ └── 確認請求來自正確的應用程式包名 ├── Nonce │ └── 防止重放攻擊的一次性隨機值 └── Timestamp └── 請求產生的時間戳記 目的: ├── 防止跨應用程式攻擊 ├── 確保請求的新鮮度 └── 防止重放攻擊 ``` **重要概念:** - **Nonce (Number used once,一次性隨機數)**:伺服器產生的隨機值,確保每個 token 唯一 - 伺服器必須追蹤並核銷使用過的 nonce #### 2. App Integrity (應用程式完整性) ``` 應用程式完整性判定: ├── PLAY_RECOGNIZED │ ├── 應用程式來自 Google Play │ ├── 簽章與 Play Store 版本一致 │ └── 未被篡改或修改 │ ├── UNRECOGNIZED_VERSION │ ├── 應用程式包名正確 │ ├── 但版本不在 Play Store 中 │ └── 可能是測試版或舊版本 │ └── UNEVALUATED └── 無法評估(網路問題等) ``` **典型場景:** - `PLAY_RECOGNIZED`:正常使用者從 Play Store 安裝 - `UNRECOGNIZED_VERSION`:開發者測試版、企業內部版 - 被拒絕:破解版、反編譯後重新打包的版本 #### 3. Device Integrity (裝置完整性) 這是 Play Integrity 最強大的部分,提供多層次的裝置完整性評估: ``` 裝置完整性等級: ├── MEETS_DEVICE_INTEGRITY (最高等級) │ ├── Google 認證的 Android 裝置 │ ├── 通過 Android 相容性測試 │ ├── 未被 Root │ └── 系統完整性良好 │ ├── MEETS_BASIC_INTEGRITY (基本等級) │ ├── 可能不是 Google 認證裝置 │ ├── 或是 Google 認證但被修改 │ └── 基本的 Android 系統相容性 │ ├── MEETS_STRONG_INTEGRITY (硬體支援等級) │ ├── 具有硬體安全模組(HSM) │ ├── 支援 Hardware-backed Keystore │ └── 提供最高等級的安全保證 │ └── MEETS_VIRTUAL_INTEGRITY (虛擬環境) └── Google 官方模擬器(用於開發測試) ``` **重要概念:** **MEETS_DEVICE_INTEGRITY:** - 代表標準的 Android 生態系統 - 大部分正常使用者的裝置 - 最常見的完整性等級 **MEETS_BASIC_INTEGRITY:** - 可能的情況: - 中國品牌手機(沒有 Google 認證) - Root 過的裝置 - 自定義 ROM - 修改過的系統 **MEETS_STRONG_INTEGRITY:** - 高階裝置才有 - 使用硬體安全晶片 - 提供 hardware-backed attestation #### 4. Account Details (帳號詳情) ``` 帳號授權狀態: ├── LICENSED │ ├── 應用程式已透過 Play Store 取得 │ └── 對免費 App:表示已下載安裝 │ └── 對付費 App:表示已購買 │ ├── UNLICENSED │ └── 應用程式未透過 Play Store 合法取得 │ └── UNEVALUATED └── 無法評估授權狀態 ``` **使用場景:** - 防止盜版 - 驗證付費應用程式的授權 - 檢測側載(Sideloading)安裝 #### 5. Environment Details (環境詳情) Environment Details 評估裝置的執行環境安全性,包含兩個主要欄位: **可能的判定值:** ``` environmentDetails { playProtectVerdict: string // Play Protect 狀態 appAccessRiskVerdict: string // 應用程式存取風險 } ``` **A. Play Protect Verdict (Play Protect 狀態)** ``` Play Protect 常見判定值(示意): ├── PLAY_PROTECT_VERDICT_UNSPECIFIED │ └── 未指定或無法判定 ├── NO_ISSUES │ └── Play Protect 已啟用且未發現問題 ├── NO_DATA │ └── 無法取得 Play Protect 資訊 ├── MEDIUM_RISK │ └── Play Protect 偵測到中度風險 └── HIGH_RISK └── Play Protect 偵測到高度風險 註:實際判定值以 Google 官方 SDK 回應為準,可能隨版本變動 ``` **Play Protect 功能:** - Google 內建的惡意軟體掃描服務 - 持續監控已安裝的應用程式 - 偵測潛在有害應用程式 (PHA) **B. App Access Risk Verdict (應用程式存取風險)** App Access Risk 會回傳 `appsDetected` 陣列,包含偵測到的應用程式類型。 **判定值分類:** 根據應用程式來源,判定值會有不同前綴: - `KNOWN_*`: Google Play 或系統預載應用程式 - `UNKNOWN_*`: 其他來源安裝的應用程式 ``` 可能的判定值: ├── KNOWN_INSTALLED / UNKNOWN_INSTALLED │ └── 偵測到已安裝的應用程式 ├── KNOWN_CAPTURING / UNKNOWN_CAPTURING │ └── 有執行中應用程式可查看螢幕畫面 ├── KNOWN_CONTROLLING / UNKNOWN_CONTROLLING │ └── 有執行中應用程式可控制裝置或攔截輸入/輸出 ├── KNOWN_OVERLAYS / UNKNOWN_OVERLAYS │ └── 有執行中應用程式可顯示疊加畫面 └── {} (空白) └── 未符合評估條件 (如裝置可信度不足) ``` **判定結果範例:** | appsDetected | 意義 | |-------------|------| | `["KNOWN_INSTALLED"]` | 只有 Play 或系統應用,無風險 | | `["KNOWN_INSTALLED", "UNKNOWN_CAPTURING"]` | 有其他應用正在擷取螢幕或輸入 | | `["KNOWN_CONTROLLING", "UNKNOWN_INSTALLED"]` | 有 Play 應用正在控制裝置,且有其他來源應用 | | `{}` | 無法評估 (裝置可信度不足等) | **重要注意事項:** - 經過 Google Play 無障礙功能審查的應用會被排除 - 工作資料夾中的應用一律標記為 `UNKNOWN_*` - 空白結果可能原因:裝置可信度不足、Android 版本過舊、Play Store 版本過舊等 **使用建議:** - 根據業務需求決定對不同風險等級的處理方式 - `CAPTURING` 和 `CONTROLLING` 應特別注意,可能影響敏感操作 - 可結合其他判定維度綜合評估 ## Play Integrity 工作流程 ### 基本流程 ```mermaid sequenceDiagram participant A as Android App participant P as Play Integrity API participant S as Your Server participant Auth as Google Auth API participant G as Google Verdict API A->>S: 請求 nonce S->>A: 返回 nonce A->>P: requestIntegrityToken(nonce) P->>G: 收集裝置資訊 G->>G: 評估完整性 G->>P: 返回加密 token P->>A: IntegrityToken A->>S: 提交 token Note over S,Auth: 第一步:取得授權 Token S->>Auth: 請求 OAuth 2.0 Access Token Auth->>S: 返回 Access Token Note over S,G: 第二步:解密並取得判定 S->>G: 解密 token (帶 Access Token) G->>S: 返回 verdict (判定結果) S->>S: 根據判定做決策 S->>A: 返回結果 ``` **關鍵步驟說明:** 1. **Nonce 生成:** - 伺服器產生隨機 nonce - 綁定到特定請求 - 防止 token 被重複使用 2. **Token 請求:** - App 呼叫 Play Integrity API - 傳入 nonce - API 收集裝置和應用資訊 3. **Token 加密:** - Google 評估完整性 - 生成加密的 token - Token 包含所有判定結果 4. **後端兩步驟 API 驗證:** **步驟 1 - 取得授權 Token:** - 使用 Service Account 憑證 - 呼叫 Google OAuth 2.0 API - 取得短期有效的 Access Token - Endpoint: `https://oauth2.googleapis.com/token` **步驟 2 - 解密並取得判定:** - 使用步驟 1 的 Access Token - 呼叫 Play Integrity API - 傳入加密的 Integrity Token - Endpoint: `https://playintegrity.googleapis.com/v1/{package}/decodeIntegrityToken` - 獲得五大維度的判定結果 **為什麼需要兩步驟?** - 安全性考量:Access Token 短期有效(通常 1 小時) - 權限隔離:Service Account 可精細控制權限 - 防止濫用:每個 API 呼叫都需要有效授權 ### Token 的特性 ``` Integrity Token 特性: ├── 加密保護 │ └── 只有 Google 和您的伺服器能解密 ├── 單次使用 │ └── Nonce 機制防止重放 ├── 有時間限制 │ └── 通常幾分鐘內有效 └── 包含完整資訊 └── 五大維度的判定結果 ``` ## 實作決策邏輯 ### 如何解讀判定結果? 不同的業務場景需要不同的信任等級: ``` 場景一:一般功能訪問 可接受的判定: ├── App Integrity: PLAY_RECOGNIZED ├── Device Integrity: MEETS_DEVICE_INTEGRITY 或 MEETS_BASIC_INTEGRITY └── 決策: 允許 場景二:敏感操作(如支付) 嚴格要求: ├── App Integrity: 必須 PLAY_RECOGNIZED ├── Device Integrity: 必須 MEETS_DEVICE_INTEGRITY 或 MEETS_STRONG_INTEGRITY ├── Account Details: LICENSED └── 決策: 拒絕任何不符合的情況 場景三:開發測試環境 寬鬆設定: ├── App Integrity: UNRECOGNIZED_VERSION (允許) ├── Device Integrity: MEETS_VIRTUAL_INTEGRITY (允許模擬器) └── 決策: 用於開發階段 ``` ### 分層處理策略 ``` 根據完整性等級分層處理: 高信任等級: ├── PLAY_RECOGNIZED + MEETS_DEVICE_INTEGRITY └── 動作: 完全訪問 中信任等級: ├── PLAY_RECOGNIZED + MEETS_BASIC_INTEGRITY └── 動作: 允許但監控,限制敏感功能 低信任等級: ├── UNRECOGNIZED_VERSION └── 動作: 限制功能,要求額外驗證 拒絕: ├── 無任何有效的 integrity 判定 └── 動作: 拒絕請求 ``` ## 常見挑戰與考量 ### 1. Root 裝置處理 ``` Root 裝置的判定: ├── 通常無法通過 MEETS_DEVICE_INTEGRITY ├── 可能通過 MEETS_BASIC_INTEGRITY └── 完全無法通過 MEETS_STRONG_INTEGRITY 處理策略: ├── 嚴格應用: 拒絕所有 Root 裝置 ├── 彈性應用: 允許但限制功能 └── 考量: 部分合法使用者可能使用 Root 裝置 ``` **建議:** - 金融、支付類應用:嚴格拒絕 - 一般應用:可以允許但監控 - 遊戲應用:視反作弊需求決定 ### 2. 中國市場考量 ``` 中國市場挑戰: ├── 許多裝置沒有 Google Play Services ├── 無法使用 Play Integrity └── 需要替代方案 替代策略: ├── 使用中國本地的完整性驗證方案 ├── 或降級使用其他驗證機制 └── reCAPTCHA + 自定義檢測 ``` ### 3. 開發與測試環境 ``` 開發環境處理: ├── Debug 版本通常是 UNRECOGNIZED_VERSION ├── 模擬器返回 MEETS_VIRTUAL_INTEGRITY └── 需要設定不同的驗證邏輯 建議做法: ├── 環境判斷 │ ├── Production: 嚴格驗證 │ ├── Staging: 中等驗證 │ └── Development: 寬鬆驗證 └── 使用 Build Variant 區分 ``` ## 與其他機制的配合 ### 三層防護中的角色 ``` 第一層: reCAPTCHA ├── 防護: 機器人、腳本攻擊 └── 所有請求都要通過 第二層: Play Integrity (Android) ├── 防護: 破解應用、模擬器、惡意環境 ├── 高風險操作必須通過 └── 提供裝置和應用完整性保證 第三層: 業務邏輯驗證 └── 應用程式特定的驗證規則 ``` ### 組合使用範例 ``` 使用者登入流程: 1. reCAPTCHA 檢查 (人機識別) ├── 分數 < 0.5: 拒絕 └── 分數 >= 0.5: 繼續 2. Play Integrity 檢查 (完整性) ├── App != PLAY_RECOGNIZED: 拒絕 ├── Device != MEETS_DEVICE_INTEGRITY: 額外驗證 └── 通過: 允許登入 3. 業務邏輯檢查 ├── 帳號狀態 ├── 登入歷史 └── 異常模式偵測 ``` ## 總結 ### Play Integrity 的核心價值 **優勢:** ✅ 強大的應用程式完整性驗證 ✅ 多層次的裝置完整性評估 ✅ 硬體級安全支援(STRONG_INTEGRITY) ✅ 整合 Google Play 生態系 ✅ 偵測 Root、破解、模擬器 ✅ Play Protect 惡意軟體防護 **適用場景:** - Android 應用程式防護 - 防止破解和逆向工程 - 遊戲反作弊 - 金融應用安全 - 付費內容保護 **局限性:** ❌ 僅限 Android 平台 ❌ 需要 Google Play Services ❌ 中國市場無法使用 ❌ Root 裝置可能被拒絕(影響部分合法使用者) ❌ 需要較複雜的判定邏輯 ### 關鍵概念回顧 1. **五大驗證維度**:全面評估請求可信度 2. **多層次完整性等級**:DEVICE/BASIC/STRONG/VIRTUAL 3. **Nonce 機制**:防止 token 重放攻擊 4. **分層處理**:根據不同信任等級採取不同策略 5. **環境感知**:開發、測試、生產環境不同處理 ### 與 Apple App Attest 的對應 Play Integrity 和 Apple App Attest 解決相同的問題,但實作方式不同: | 特徵 | Play Integrity | App Attest | |------|----------------|------------| | 平台 | Android | iOS | | 核心 | Play Services | Secure Enclave | | 完整性等級 | 多層次(4種) | 二元(通過/失敗) | | 硬體支援 | STRONG_INTEGRITY | 強制硬體綁定 | | 實作複雜度 | 中 | 高 | --- 在下一篇文章中,我們將深入探討 **Apple App Attest**,了解 iOS 平台如何利用硬體安全模組提供最高等級的完整性保證。 ## 參考資源 - [Play Integrity API 官方文件](https://developer.android.com/google/play/integrity) - [Integrity Verdict 解讀指南](https://developer.android.com/google/play/integrity/verdict) - [Play Integrity 最佳實務](https://developer.android.com/google/play/integrity/overview#best-practices) - [Classic API 遷移指南](https://developer.android.com/google/play/integrity/migrate)