返回所有文章

將遊戲中散布的 API 金鑰與分析用金鑰分開

散布給玩家的遊戲需要傳送遙測的權限,建置比較工作需要讀取資料的權限。兩者共用一個憑證,就可能讓人從遊戲安裝套件中擷取出分析資料的存取權限。

在 Framedash 中,遊戲使用 Ingest 金鑰,一般分析使用另一把 Read-only 金鑰。兩種金鑰都以 fd_ 開頭。伺服器根據金鑰中儲存的 scope(允許執行的操作集合)進行授權,金鑰名稱和前綴並不能決定權限。

依操作選擇預設組合

專案儀表板的 API 金鑰頁面提供以下預設組合。各組合的 scope 見 API 概述。

預設組合儲存的 scope用途
Ingestevents:write傳送 SDK 遙測
Read-onlyanalytics:read讀取彙總資料、專案狀態與設定,比較建置
Read & Writeanalytics:read, resources:write除了讀取,也可修改地圖、內容與警示
Fullanalytics:read, resources:write, data:admin進一步執行原始 SQL、匯出資料與刪除玩家遙測

Full 不包含 events:write。 它不能取代遊戲使用的 Ingest 金鑰。這些預設組合涵蓋不同操作的權限,並不是高一級就包含低一級所有操作的階層關係。

使用原始 SQL 時,尤其要留意授予的權限。即使是 SELECT,也能傳回玩家層級的資料列,因此 /api/v1/query 要求 data:admin。這個 scope 同時允許匯出與刪除玩家資料。為了執行一條查詢而選擇 Full,也會授予另外兩種操作的權限。如果彙總 API 已能回答問題,就優先使用它;更廣的權限只交給確實需要它的受控處理程序。

金鑰綁定至一個專案。傳入其他專案 ID,並不會得到該專案的存取權限。擁有 scope 也不能繞過帳戶限制或請求速率限制。

不把分析憑證放進散布的建置

兩條獨立路徑:散布的遊戲只持有 events:write 金鑰,向 Ingest API 傳送事件;受控分析環境儲存 analytics:read 金鑰,從 Web API 讀取資料。兩種環境之間不複製金鑰。

圖中上方的路徑將 SDK 事件傳送到 https://ingest.framedash.dev/v1/events,下方的讀取路徑使用 https://app.framedash.dev/api/v1。分析憑證應儲存在受控的開發機器、後端或可信任的 CI 執行器上。不要將它們放進遊戲資產、Web 遊戲的 JavaScript、可下載的設定或公開的建置產物。

應假設散布到用戶端的金鑰可以被擷取。把值從原始碼移到建置時的環境變數,可以讓它不再出現在那份原始檔中;但如果建置過程把它複製進最終安裝套件,它仍然不保密。不要因為做了混淆,就散布權限更高的金鑰。OWASP 關於應用程式套件內敏感資料的說明也討論了這種擷取風險。

進行效能檢查時,遊戲處理程序需要 Ingest 金鑰,負責比較的 CLI 需要 Read-only 金鑰。只把憑證交給需要它的處理程序。CLI 的 --api-key-file 選項可以從私人檔案讀取金鑰,避免將金鑰值放在命令列引數中。但能存取同一台機器或工作區檔案的程式碼,仍然可能讀到這個檔案。

Ingest 金鑰暴露後仍能做什麼

Ingest 金鑰不能讀取分析資料、修改地圖或刪除既有的玩家遙測,但它可以向所屬專案提交事件。擷取到金鑰的人,可以在擷取服務接受的格式與限制範圍內傳送偽造遙測。

這些事件可能污染量測結果,也可能占用擷取處理能力或事件額度。API 金鑰驗證的是傳送憑證所具備的權限,無法證明某個影格時間樣本來自未經修改的遊戲,也無法證明申報的玩家 ID 或建置 ID 真實。僅授予遙測寫入權限,不能阻止偽造事件。

用於發布決策的受控測試資料,應盡可能與公開用戶端的遙測分開。需要隔離時,可以使用不同專案。只換一個由用戶端填寫的建置 ID,不等於驗證了資料來源。出現異常增長時,應與自己的執行器紀錄核對。如果威脅模型要求更嚴格的來源驗證,就需要在自己控制的後端設計驗證流程;僅靠金鑰分離無法提供這種驗證。

限制 CI 與代理的存取範圍

接收 CI secret 的程式碼可以使用它。不要在能讀取分析或管理金鑰的工作中執行不可信任提取要求裡的程式碼。GitHub 的安全使用指南介紹了不可信任程式碼的簽出、指令碼注入,以及日誌遮罩的限制。應審查工作流程變更,將具有權限的分析工作與不可信任的建置分開。

為分析代理設定憑證時,先從 analytics:read 與調查必需的工具開始。遙測文字、存放庫檔案和工具結果都應視為不可信任的輸入。其中出現的指令,不應成為存取秘密資訊、轉送憑證或擴大 scope 的授權依據。不要把金鑰貼到提示詞或工具輸出中。

最小權限可以限制一次錯誤工具呼叫所能執行的操作。不過,Read-only 金鑰仍能讀取專案資訊,因此還要控制代理可以把結果傳送到哪裡。「不要修改資料」這樣的提示詞,不能取代伺服器強制執行的 scope 限制。

不傳送測試事件也能驗證金鑰

GET https://app.framedash.dev/api/v1/whoami 透過 X-API-Key 驗證 API 金鑰,Ingest 金鑰也適用。不必為了確認金鑰而上傳遙測。這個端點只接受 API 金鑰,不接受 OAuth Bearer 權杖。

下面的 Python 指令碼從秘密管理工具提供給該處理程序的環境變數中讀取金鑰,不將其放進命令列引數,也不列印金鑰值。執行時不要開啟環境變數傾印或除錯日誌。

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://app.framedash.dev/api/v1/whoami",
)
request.add_unredirected_header("X-API-Key", os.environ["FRAMEDASH_API_KEY"])
with urllib.request.urlopen(request, timeout=15) as response:
    data = json.load(response)["data"]
print(json.dumps({"projectId": data["projectId"], "scopes": data["scopes"]}))

檢查傳回的專案 ID 與 scope 是否符合該工作的用途。僅限 Ingest 的金鑰會傳回 projectId 與 scopes,具有分析或管理 scope 的金鑰會收到額外中繼資料。無效或已撤銷的金鑰傳回 401;帳戶限制和請求速率限制等檢查也可能拒絕請求。驗證成功只能確認金鑰目前綁定的專案與權限,不能確認已擷取資料的完整性或真實性。

下次發布前,檢查遊戲安裝套件與 CI 憑證設定。如果分析金鑰進入了公開產物,應撤銷它,在受控使用端替換新金鑰,並移除暴露的副本。已經散布的 Ingest 金鑰則需要配合用戶端更新安排更換:撤銷舊金鑰,也會讓仍使用它的用戶端停止回報遙測。記錄每個建置或工作使用的金鑰,才能在事故發生前看清更換的影響。