安全的移動應用遙測代理
移動應用程式分發到您無法控制的裝置。任何編譯到 React Native 包、Swift 應用程式、Kotlin 應用程式或 Flutter 二進位制檔案中的內容最終都可以被檢查。請勿在應用程式中傳送 Telemetry API 金鑰、傳送到應用程式的遠端設定值或客戶端可讀的環境檔案。
相反,將一個小事件傳送到您的應用程式擁有的經過身分驗證的端點。該端點驗證固定合約,新增受信任的伺服器上下文,並使用伺服器端金鑰轉發事件。
移動端代理示意圖:應用將事件傳送至自己的 API,API 驗證身分、校驗允許的事件並限制請求速率,再轉發至 Telemetry。 移動應用不會收到 Telemetry 的攝取金鑰。
當這個模式適合時
使用移動代理來獲取產品里程碑、有限效能測量、同步結果、受控錯誤類別和發布品質訊號。範例包括:
- 本地到伺服器同步達到最終結果後
mobile_sync_completed。 mobile_screen_ready用於一小組命名螢幕和測量的持續時間。- 伺服器確認持久結果後
mobile_purchase_flow_completed。 mobile_api_request_completed用於取樣、分類的依賴性結果。
這不能替代崩潰符號、裝置日誌、分散式追蹤或精確的稽核分類帳。移動交付受到連線、後台執行限制、應用程式終止、同意和客戶端時鐘品質的影響。將專業診斷保留在其專業系統中,並僅傳送 SQL 分析所需的結果。
定義客戶合約
客戶端應從事件名稱和欄位的版本列表中進行選擇。它不應選擇 Telemetry 資料表名、傳送任意屬性包或轉發異常訊息。
{
"event_name": "mobile_sync_completed",
"event_version": 1,
"event_id": "0196f37e-6e83-7b75-9d04-6b8283b35f74",
"occurred_at": "2026-07-30T18:42:11.150Z",
"status": "success",
"duration_ms": 842,
"item_count": 12,
"network_type": "wifi"
}
保持尺寸有界。優先選擇受控的 screen_name 而不是原始路由,優先選擇 error_type 列舉而不是異常字串,優先選擇粗略的 network_type 而不是網路識別符號。請勿包含存取權杖、裝置廣告識別符號、聯絡人資料、訊息內容、檔案路徑、剪貼簿資料、自由格式搜尋文字或原始 URL。
event_id支援重試重複資料刪除。 occurred_at 記錄客戶端觀察,但代理還應新增伺服器接收的時間戳。使用伺服器時間戳進行新鮮度和攝取監控,因為裝置時鐘可能是錯誤的。
實施應用程式擁有的端點
以下 TypeScript 草圖顯示了邊界。將身分驗證和速率限制調整為 API 已使用的框架。
const allowedEvents = {
mobile_sync_completed: {
statuses: new Set(["success", "failed", "cancelled"]),
maximumDurationMs: 300_000,
maximumItemCount: 10_000,
},
} as const;
export async function postMobileTelemetry(request: Request) {
const actor = await authenticateApplicationRequest(request);
if (!actor) return new Response("unauthorized", { status: 401 });
await enforceRateLimit({
accountId: actor.accountId,
deviceSessionId: actor.deviceSessionId,
});
const body = await readBoundedJson(request, { maximumBytes: 4096 });
const policy = allowedEvents[body.event_name as keyof typeof allowedEvents];
if (
!policy ||
body.event_version !== 1 ||
!isUuid(body.event_id) ||
!policy.statuses.has(body.status) ||
!isIntegerInRange(body.duration_ms, 0, policy.maximumDurationMs) ||
!isIntegerInRange(body.item_count, 0, policy.maximumItemCount)
) {
return new Response("invalid event", { status: 422 });
}
await telemetry.log("mobile_sync_completed", {
event_id: body.event_id,
event_version: 1,
occurred_at: parseBoundedClientTimestamp(body.occurred_at),
received_at: new Date().toISOString(),
status: body.status,
duration_ms: body.duration_ms,
item_count: body.item_count,
network_type: normalizeNetworkType(body.network_type),
account_id: actor.accountId,
app_platform: actor.platform,
app_version: actor.appVersion,
environment: process.env.APP_ENV ?? "development",
});
return new Response(null, { status: 202 });
}
API 決定Telemetry 事件名稱。它從受信任的伺服器狀態派生身分、平臺、環境和任何授權上下文,而不是從客戶端接受這些值。如果端點支援多個事件,請為每個事件提供獨立的模式和測試裝置。
應用四個伺服器端控制元件
認證
需要 API 的其餘部分使用相同的簽名應用程式會話或安裝憑據。 CORS 不是移動安全邊界,僅自定義標頭並不能證明誰傳送了請求。
允許名單
拒絕未知的事件名稱、欄位、列舉值、超大字串、無效數字、未來時間戳和超出小尺寸限制的正文。允許名單既是隱私控制又是基數控制。
速率限制
透過經過身分驗證的帳戶和適當的安裝或會話識別符號進行限制。還施加了全球上限。當客戶端超出限制時,返回正常的應用程式錯誤,而不會無限期地重試。
新增可信上下文
代理應新增帳戶識別符號、伺服器接收時間、環境和經過驗證的應用程式版本(如果這些值可用)。如果帳戶識別符號在您的上下文中敏感,請在收集之前對其進行一致的假名化,並記錄誰可以反轉對映。
選擇移動交付行為
對於 React Native 和 Flutter,請使用已經負責經過身分驗證的 API 請求的平臺 HTTP 客戶端。對於本機 iOS 和 Android,請使用應用程式使用的相同 URLSession 或 HTTP 堆疊。端點和事件契約在不同平臺上應該保持相同。
當離線交付很重要時,保持一個小的有界佇列。限制專案數量和壽命,丟棄超出記錄視窗的事件,並使用帶有抖動的指數退避。不要讓分析重試延遲產品操作。在嘗試中保留相同的 event_id ,以便伺服器可以進行重複資料刪除。
有些結果最好由伺服器發出。購買、訂閱更改、存取策略決策或完成的匯入僅在後端提交後才具有權威性。讓伺服器直接發出這些結果,而不是信任客戶端斷言。
查詢並驗證結果
傳送一個合成的成功、失敗、取消、無效負載、未經身分驗證的請求、限速突發、離線重試和重複的 event_id。然後檢查有界樣本:
SELECT
received_at,
event_id,
app_platform,
app_version,
status,
duration_ms,
item_count
FROM mobile_sync_completed
ORDER BY received_at DESC
LIMIT 50;
在推出之前,請驗證:
- 提供的應用程式二進位制檔案和 JavaScript 捆綁包不包含 Telemetry API 金鑰。
- 未知的事件和欄位會被拒絕,而不是默默地轉發。
- 不存在原始異常文字、URL、使用者輸入、憑據和裝置識別符號。
- 重試保留一個
event_id,並且重複交付不會增加結果計數。 - 儀表板在比率和百分位數旁邊顯示樣本計數。
- 同意、保留、刪除和帳戶刪除行為符合應用程式策略。
需要規劃的故障模式
將代理視為盡力可觀測性,除非該事件是單獨設計的持久業務工作流程的一部分。通常應記錄 Telemetry 超時並對其進行限制,而不會導致移動產品操作失敗。監控代理拒絕率、轉發失敗、佇列壽命和事件新鮮度,以便靜默檢測中斷看起來不像產品使用率下降。
不要自動接受任意客戶端事件以“使除錯更容易”。這將端點變成未經審查的資料收集表面。僅在檢視其目的、型別、基數、隱私分類和刪除要求後才新增新的版本化欄位或事件。