# Expo API 金鑰安全：哪些能放進 App？

> Supabase 公開金鑰可以放在 App 裡，伺服器密鑰只能放在伺服器上。再用兩個測試帳號實際驗證存取權限。

原始頁面：[Expo API 金鑰安全：哪些能放進 App？](https://devoria.fr/zh-hant/blog/expo-api-key-security-supabase)
作者：[Mehdi Azizi](https://devoria.fr/zh-hant/mehdi-azizi)
發布日期：2026-09-29
內容最後修訂：2026-10-09


## 環境變數不一定是機密

在 Expo App 裡，前綴為 `EXPO_PUBLIC_` 的變數是給 App 程式碼用的，不應該放伺服器端的機密。Expo 說明這些值會被打包進編譯後的 JavaScript，App 使用者讀得到。所以把金鑰移到 `.env` 檔案，並不足以保護它。[來源：Expo 環境變數](https://docs.expo.dev/guides/environment-variables/)。

在叫 AI「把 API 接上去」之前，先把你要交給它的東西分類：服務網址、本來就設計成公開的金鑰，或是能執行特權操作的金鑰。這個分類決定了程式碼該在哪裡執行。

下表是設計用的對照表，不是對你 App 的稽核。

| 項目                                        | 放在哪裡                   | 要檢查什麼                                                         |
| ------------------------------------------- | -------------------------- | ------------------------------------------------------------------ |
| 後端的公開網址                              | App 設定                   | 指向正確的環境。                                                   |
| Supabase publishable 金鑰，或舊版 anon 金鑰 | 權限設定正確的話可放在 App | 資料規則確實擋住對其他使用者帳號的存取。                           |
| Supabase secret 或 service_role 金鑰        | 只放伺服器                 | 不出現在行動版 bundle，也不出現在用戶端看得到的日誌。              |
| AI 服務商的密鑰                             | 只放伺服器                 | App 呼叫你的伺服器，由伺服器先檢查使用者和用量限制，再呼叫服務商。 |

Supabase 區分給用戶端用的金鑰，以及給受信任環境用的密鑰。公開金鑰用來識別專案，它不能取代資料權限。[來源：Supabase API 金鑰](https://supabase.com/docs/guides/getting-started/api-keys)。

## 範例：一個虛構的閱讀筆記 App

假設有個 App，Léa 和 Sami 在裡面記錄自己的書和私人筆記。這個例子是用來準備測試的，不是 Devoria 某個 App 的實測結果。

正常流程看起來沒問題：Léa 登入後看到自己的筆記。但這還沒回答真正重要的問題：Léa 送出想讀取 Sami 筆記的請求時，伺服器會拒絕嗎？

在介面上加個篩選，例如「只顯示目前登入使用者的筆記」，可以改善畫面呈現。但授權也必須在資料端執行。在 Supabase 中，Row Level Security 規則可以依照 session 限制能存取的資料列。Supabase 建議對 API 開放的資料表啟用它，並說明讀取和寫入的政策。[來源：Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security)。

在你自己的測試專案裡，把每則筆記綁定到擁有者，並分別定義誰能讀取、建立、修改和刪除。檔案也要檢查：保護了資料庫的某一列，不代表圖片就是私密的。

## 用兩個測試帳號執行的驗收流程

準備兩個你能控制的帳號，各放一本不同的書和一則好辨認的短筆記。在獲得授權的測試環境中使用虛構資料。

1. **讀取自己的筆記。** 帳號 A 找得到筆記 A。
2. **從 A 讀取 B 的筆記。** 請求不會洩漏其私人內容。
3. **從 A 修改 B 的筆記。** 伺服器拒絕，筆記 B 維持不變。
4. **從 A 以 B 的名義建立資料。** 伺服器拒絕這個歸屬。
5. **沒有 session 時讀取。** 不回傳任何私人內容。
6. **從 A 開啟 B 的私人檔案。** 檔案無法存取。

記下實際結果、測試的版本和出現的錯誤（如果有）。「規則已經啟用」不算測試結果。[資源頁面中的驗收表](https://devoria.fr/zh-hant/resources)可以當作保存這些證據的基礎。

## 讓付費呼叫經過你的伺服器

如果有個功能是用[AI API](https://devoria.fr/zh-hant/blog/guideline-5-1-2-third-party-ai-att-data-sharing)摘要一本書，流程可以是：App → 你的伺服器 → 服務商 → 你的伺服器 → App。密鑰留在伺服器上。光有這個架構還不夠：伺服器本身的存取也要受到控管。

在這個虛構範例中，伺服器特別要檢查 session、確認這本書屬於該使用者、限制重複請求，並在服務商沒回應時回傳看得懂的錯誤。用戶端不能自己決定某個使用者享有付費權限。

準備四個測試：未登入的使用者、其他帳號的書、達到用量上限，以及服務商無法使用。最後一項可以確認 App 會離開載入狀態，而且不會遺失使用者輸入的內容。

## 你可以請程式助手做什麼

下面是一段審查指令，可以依照你的 repo 調整，但不要把機密值貼進去：

> 列出行動版程式碼和伺服器使用的變數，只顯示名稱。找出用戶端上的特權呼叫。針對私人資料，描述讀取和寫入的控管方式，然後提出一套用兩個測試帳號進行的驗收流程。未經確認，不要輪替任何金鑰，也不要修改正式環境。

對照相關程式碼閱讀它的回答。助手可以發現不一致之處，但它的回答不能取代實際執行測試。[用 Claude Code 開發 App](https://devoria.fr/zh-hant/blog/claude-code-iphone-app-tutorial) 這篇指南說明了如何拆分這項工作。

## 繼續開發 App 之前

你必須能簡單說明三件事：哪些值是公開的、哪些操作經過伺服器，以及哪些測試證明一個帳號看不到另一個帳號的資料。只要其中一點還不清楚，就先釐清，再加新功能。

[開發 iPhone App](https://devoria.fr/zh-hant/expertise/build-an-iphone-app) 這一頁把這個步驟放回整個專案中來看。想按部就班前進的話，[iOS Kit](https://devoria.fr/zh-hant/kits/ios) 提供四個步驟的流程，以及已經內建帳號和 AI 功能的起始程式碼。如果你不確定該從哪一步接著做，[免費診斷](https://devoria.fr/zh-hant/diagnostic)會幫你把專案理出順序，並寄給你我的 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 的金鑰？

請它列出行動版程式碼和伺服器的變數，只顯示名稱，不要貼上你的機密值。也請它找出用戶端上的特權呼叫，並提出一套用兩個測試帳號進行的驗收流程。禁止它在未經確認的情況下輪替金鑰或修改正式環境。它的回答不能取代實際執行測試。


## 你的專案

[iOS Kit](https://devoria.fr/zh-hant/kits/ios)：用 Claude Code 打造你的 iPhone App：我的 App 所用的 Starter Code、檢查成果的 skills，以及 Apple Review Kit、App Store Screenshots Kit 與 ASO Kit。129.99 €。
