Expo API 金鑰安全:哪些能放進 App?
作者:Mehdi Azizi
更新於 ,7 分鐘
Supabase 公開金鑰可以放在 App 裡,伺服器密鑰只能放在伺服器上。再用兩個測試帳號實際驗證存取權限。
環境變數不一定是機密
在 Expo App 裡,前綴為 EXPO_PUBLIC_ 的變數是給 App 程式碼用的,不應該放伺服器端的機密。Expo 說明這些值會被打包進編譯後的 JavaScript,App 使用者讀得到。所以把金鑰移到 .env 檔案,並不足以保護它。來源:Expo 環境變數。
在叫 AI「把 API 接上去」之前,先把你要交給它的東西分類:服務網址、本來就設計成公開的金鑰,或是能執行特權操作的金鑰。這個分類決定了程式碼該在哪裡執行。
下表是設計用的對照表,不是對你 App 的稽核。
| 項目 | 放在哪裡 | 要檢查什麼 |
|---|---|---|
| 後端的公開網址 | App 設定 | 指向正確的環境。 |
| Supabase publishable 金鑰,或舊版 anon 金鑰 | 權限設定正確的話可放在 App | 資料規則確實擋住對其他使用者帳號的存取。 |
| Supabase secret 或 service_role 金鑰 | 只放伺服器 | 不出現在行動版 bundle,也不出現在用戶端看得到的日誌。 |
| AI 服務商的密鑰 | 只放伺服器 | App 呼叫你的伺服器,由伺服器先檢查使用者和用量限制,再呼叫服務商。 |
Supabase 區分給用戶端用的金鑰,以及給受信任環境用的密鑰。公開金鑰用來識別專案,它不能取代資料權限。來源:Supabase API 金鑰。
範例:一個虛構的閱讀筆記 App
假設有個 App,Léa 和 Sami 在裡面記錄自己的書和私人筆記。這個例子是用來準備測試的,不是 Devoria 某個 App 的實測結果。
正常流程看起來沒問題:Léa 登入後看到自己的筆記。但這還沒回答真正重要的問題:Léa 送出想讀取 Sami 筆記的請求時,伺服器會拒絕嗎?
在介面上加個篩選,例如「只顯示目前登入使用者的筆記」,可以改善畫面呈現。但授權也必須在資料端執行。在 Supabase 中,Row Level Security 規則可以依照 session 限制能存取的資料列。Supabase 建議對 API 開放的資料表啟用它,並說明讀取和寫入的政策。來源:Row Level Security。
在你自己的測試專案裡,把每則筆記綁定到擁有者,並分別定義誰能讀取、建立、修改和刪除。檔案也要檢查:保護了資料庫的某一列,不代表圖片就是私密的。
用兩個測試帳號執行的驗收流程
準備兩個你能控制的帳號,各放一本不同的書和一則好辨認的短筆記。在獲得授權的測試環境中使用虛構資料。
- 讀取自己的筆記。 帳號 A 找得到筆記 A。
- 從 A 讀取 B 的筆記。 請求不會洩漏其私人內容。
- 從 A 修改 B 的筆記。 伺服器拒絕,筆記 B 維持不變。
- 從 A 以 B 的名義建立資料。 伺服器拒絕這個歸屬。
- 沒有 session 時讀取。 不回傳任何私人內容。
- 從 A 開啟 B 的私人檔案。 檔案無法存取。
記下實際結果、測試的版本和出現的錯誤(如果有)。「規則已經啟用」不算測試結果。資源頁面中的驗收表可以當作保存這些證據的基礎。
讓付費呼叫經過你的伺服器
如果有個功能是用AI API摘要一本書,流程可以是:App → 你的伺服器 → 服務商 → 你的伺服器 → App。密鑰留在伺服器上。光有這個架構還不夠:伺服器本身的存取也要受到控管。
在這個虛構範例中,伺服器特別要檢查 session、確認這本書屬於該使用者、限制重複請求,並在服務商沒回應時回傳看得懂的錯誤。用戶端不能自己決定某個使用者享有付費權限。
準備四個測試:未登入的使用者、其他帳號的書、達到用量上限,以及服務商無法使用。最後一項可以確認 App 會離開載入狀態,而且不會遺失使用者輸入的內容。
你可以請程式助手做什麼
下面是一段審查指令,可以依照你的 repo 調整,但不要把機密值貼進去:
列出行動版程式碼和伺服器使用的變數,只顯示名稱。找出用戶端上的特權呼叫。針對私人資料,描述讀取和寫入的控管方式,然後提出一套用兩個測試帳號進行的驗收流程。未經確認,不要輪替任何金鑰,也不要修改正式環境。
對照相關程式碼閱讀它的回答。助手可以發現不一致之處,但它的回答不能取代實際執行測試。用 Claude Code 開發 App 這篇指南說明了如何拆分這項工作。
繼續開發 App 之前
你必須能簡單說明三件事:哪些值是公開的、哪些操作經過伺服器,以及哪些測試證明一個帳號看不到另一個帳號的資料。只要其中一點還不清楚,就先釐清,再加新功能。
開發 iPhone App 這一頁把這個步驟放回整個專案中來看。想按部就班前進的話,iOS Kit 提供四個步驟的流程,以及已經內建帳號和 AI 功能的起始程式碼。如果你不確定該從哪一步接著做,免費診斷會幫你把專案理出順序,並寄給你我的 Apple 防退件檢查清單。
常見問題
Expo App 的 API 密鑰要放在哪裡?
放在你的伺服器上,絕對不要放在 App 裡。Supabase secret 或 service_role 金鑰,以及 AI 服務商的密鑰,都只能留在伺服器端。App 呼叫你的伺服器,由伺服器先檢查使用者和用量限制,再呼叫服務商。確認這些金鑰都沒有出現在行動版 bundle,也沒有出現在用戶端看得到的日誌裡。
.env 檔案能保護 Expo 裡的 API 金鑰嗎?
光靠它不行。前綴為 EXPO_PUBLIC_ 的變數是給 App 程式碼用的,不應該放伺服器端的機密。Expo 說明這些值會被打包進編譯後的 JavaScript,App 使用者讀得到。所以把金鑰移到 .env 檔案,並不足以保護它。
公開 API 金鑰和密鑰有什麼不同?
公開金鑰本來就設計成會隨 App 發佈:它用來識別專案,但不能取代資料權限。密鑰能執行特權操作,只能用在受信任的環境。在 Supabase,publishable 金鑰或舊版 anon 金鑰,在權限設定正確的前提下可以留在 App 裡。secret 和 service_role 金鑰則留在伺服器上。
怎麼從 Expo App 呼叫 AI API 又不暴露金鑰?
讓呼叫經過你的伺服器:App 呼叫伺服器,伺服器呼叫服務商,再把回應傳回 App。密鑰留在伺服器上。伺服器還要檢查 session、限制重複請求,並在服務商沒回應時回傳看得懂的錯誤。用戶端不能自己決定某個使用者享有付費權限。
怎麼確認每個使用者只看得到自己的資料?
準備兩個你能控制的測試帳號,各放一則好辨認的筆記。從帳號 A 嘗試讀取、修改、以帳號 B 的名義建立資料,再嘗試開啟 B 的私人檔案。也要在沒有 session 的情況下測試:每個請求都應該被拒絕,或不洩漏任何內容。記下實際結果,因為「規則已經啟用」不算測試結果。
怎麼請 AI 檢查我 App 的金鑰?
請它列出行動版程式碼和伺服器的變數,只顯示名稱,不要貼上你的機密值。也請它找出用戶端上的特權呼叫,並提出一套用兩個測試帳號進行的驗收流程。禁止它在未經確認的情況下輪替金鑰或修改正式環境。它的回答不能取代實際執行測試。