如何在你的 App 中妥善保管 API 金鑰
要妥善保管 API 金鑰,請把它們存為主機上的機密或環境變數,只在伺服器端程式碼中使用,並且絕對不要把它們貼到聊天、程式檔案、截圖或 Git 儲存庫中。讓每個金鑰只擁有它所需的最低權限,並在供應商那裡設定支出上限。如果金鑰曾經外洩,就進行輪替:建立新金鑰並刪除舊的,而不是只把它藏起來。
API 金鑰就是服務的密碼。你的 OpenAI 金鑰可以讓別人用你的錢使用 AI;你的 Stripe 私密金鑰可以讓別人發出退款;你的電子郵件服務金鑰可以讓別人以你的名義寄信。AI 建構工具很擅長把這些金鑰接上線,但不一定會留意它們最後會出現在哪裡,因此本指南會說明如何讓它們保持安全,以及如何進行檢查。
公開金鑰與私密金鑰
並非每個金鑰都是機密。了解兩者的差異,才不會對錯誤的金鑰過度緊張,而忽略了真正需要保護的金鑰。
| 類型 | 範例 | 能否放在瀏覽器中? |
|---|---|---|
| 可公開金鑰(Publishable / public keys) | Stripe 的 pk_… 金鑰、只限你網域使用的地圖金鑰、部分分析用 ID | 可以,這就是它們設計的用途 |
| 私密金鑰(Secret keys) | Stripe 的 sk_…、OpenAI 與 Anthropic 金鑰、電子郵件服務金鑰、資料庫密碼 | 絕對不行 |
| 服務或管理員金鑰(Service/admin keys) | 可以繞過託管資料庫存取規則的金鑰 | 絕對不行,應視為最敏感的一類 |
如果你不確定某個金鑰屬於哪一類,請查看供應商的文件。拿不定主意時,就當作機密來處理。
第一步:把金鑰存為機密,而不是寫在程式碼中
金鑰應該放在主機的環境變數或機密設定中。你的程式碼會在執行時依名稱讀取它們(例如 process.env.OPENAI_API_KEY),因此金鑰的值永遠不會出現在你的檔案中。若想了解背景知識,請參閱什麼是環境變數與機密。
把每個 API 金鑰從程式碼中移到環境變數。列出你找到的每個金鑰、它原本所在的檔案,以及你使用的變數名稱。不要顯示它們的值。
接著確認沒有任何遺漏:
搜尋整個專案,包括設定檔與任何 .env 檔案,找出任何看起來像 API 金鑰或密碼的內容。回報檔案與行號,不要回報值。
第二步:私密金鑰只在伺服器端使用
這是最重要的規則。瀏覽器收到的任何內容,訪客都能讀取;頁面原始碼與 JavaScript 檔案都能在開發人員工具中看到。
因此,如果 App 需要呼叫 OpenAI,瀏覽器應該呼叫你的伺服器,再由你的伺服器使用金鑰呼叫 OpenAI。金鑰永遠不會離開伺服器。
聊天功能目前直接從瀏覽器呼叫 OpenAI。請把這個呼叫移到伺服器端的 API 路由,該路由從環境變數讀取 OPENAI_API_KEY。瀏覽器只應呼叫我們的路由。這個路由需要登入才能使用。
前端框架中有一個常見陷阱要注意:帶有公開前綴的變數,例如 Vite 的 VITE_、Next.js 的 NEXT_PUBLIC_,會被刻意打包進瀏覽器程式碼中。即使私密金鑰「放在環境變數裡」,只要使用了這些前綴,它就會外洩。
第三步:測試是否有任何外洩
不要相信設定已經生效,請實際檢查正式網站:
- 在瀏覽器中開啟已發布的 App。
- 開啟開發人員工具,然後切換到 Sources 或 Network 分頁。
- 在所有檔案中搜尋每個私密金鑰的開頭字元(例如
sk_或sk-)。 - 檢查 App 發出的網路請求。如果請求直接從瀏覽器送往付費的 AI 服務供應商,就是危險信號。
如果發現私密金鑰,請把它移到伺服器端(第二步),並進行輪替(第六步),因為它已經是公開的了。
第四步:限制每個金鑰能做的事
許多供應商允許你限制金鑰的權限:
- 範圍限定或受限的金鑰,只能執行你的 App 所需的操作。例如 Stripe 支援具有特定權限的受限金鑰。
- 對必須公開的金鑰(例如地圖金鑰)設定網域或 IP 限制。
- 為每個 App 與每個環境使用不同的金鑰,如此一來,一個金鑰外洩時不會暴露所有內容,撤銷其中一個也不會影響其他金鑰。
- 開發時使用測試金鑰,只在已發布的 App 中使用正式金鑰。
第五步:為損害設定上限
即使金鑰受到良好的保護,仍可能透過你自己的 App 被濫用,例如有人用程式對你的 AI 功能呼叫數千次。
- 在每個付費的供應商處設定支出上限或提醒。
- 任何每次呼叫都需要花錢的功能,都要求登入。
- 加入每位用戶的速率限制。參閱什麼是速率限制。
為 /api/chat 加入限制:每位用戶每小時最多 30 次 AI 請求。達到限制時,回傳清楚的訊息。拒絕未登入用戶的請求。
第六步:輪替外洩的金鑰
如果私密金鑰出現在不該出現的地方,例如聊天訊息、提交紀錄、截圖、支援工單或瀏覽器程式碼中,就應該假設它已經被盜用。
- 在供應商那裡建立新金鑰。
- 在你 App 的設定中更新機密。
- 重新部署或重新發布,讓正式 App 使用新金鑰。
- 在供應商那裡刪除舊金鑰。
- 檢查供應商的用量紀錄,看看是否有你不認識的活動。
刪除聊天訊息或 Git 提交並不足夠。Git 歷史會保留舊版本,而任何公開的內容都可能已經被複製。
常見錯誤
- 把金鑰貼進提示中。 它現在已經存在於聊天紀錄中。請改用機密表單。
- 在私密變數上使用公開前綴。
VITE_OPENAI_API_KEY會把金鑰送給每一位訪客。 - 提交
.env檔案。 在第一次推送之前,確認它已列在.gitignore中。 - 所有地方都用同一個金鑰。 測試與正式環境,以及每個 App,都應使用不同的金鑰。
- 沒有支出上限。 外洩或被濫用的金鑰若沒有上限,可能在你發現之前就累積出龐大的帳單。
- 隱藏而非輪替。 金鑰一旦外洩,只有換成新金鑰才能解決問題。
- 截圖中含有金鑰。 為了求助而分享設定頁面前,請先裁切或模糊處理。
檢查清單
- 每個金鑰都存為機密或環境變數,而不是寫在程式碼中。
- 沒有
.env檔案或金鑰被提交到 Git。 - 私密金鑰只在伺服器端程式碼中使用。
- 沒有私密變數使用
VITE_或NEXT_PUBLIC_之類的公開前綴。 - 我已搜尋正式網站的 JavaScript,確認沒有任何金鑰前綴。
- 供應商允許的情況下,金鑰都已設定範圍或限制。
- 測試與正式金鑰是分開的。
- 付費功能需要登入,並有每位用戶的限制。
- 每個付費供應商都設定了支出上限或提醒。
- 我知道如何輪替每個金鑰,且任何曾經外洩的金鑰都已輪替。
在 Mythex 上妥善保管金鑰
Mythex 透過兩種方式讓金鑰遠離你的程式碼與聊天:
- 機密請求卡片。 當 Agent 需要金鑰時,會在聊天中顯示一張卡片,讓你在表單欄位中輸入值,而不是在訊息輸入框中輸入;金鑰會存為專案機密。參閱聊天中的機密。
- 專案設定 → Secrets,或在聊天中輸入
/secrets,讓你自行新增或變更金鑰。參閱環境變數與機密。
變更已發布 App 的機密後,請重新發布,讓正式 App 套用新的設定。匯出的專案不包含機密,因此在你下次執行程式碼的任何地方,都需要重新加入。如果金鑰曾經出現在聊天中,請在供應商那裡進行輪替。
上線前安全檢查的其餘部分,請依照AI 建構 App 的安全檢查清單逐項完成。如果你正在加入 AI 功能,如何使用 LLM API 會更深入地說明金鑰與成本。
常見問題
把 API 金鑰放在前端程式碼中安全嗎?
只有在服務供應商本來就設計為公開的金鑰時才安全,例如 Stripe 的可公開金鑰,或是限制只能用於你網域的地圖金鑰。任何可以花錢或讀取私人資料的金鑰都必須留在伺服器端,因為傳送到瀏覽器的任何內容,任何人都能讀取。
如果我把 API 金鑰貼到聊天或公開的程式碼庫中,該怎麼辦?
請進行輪替:在供應商那裡建立新金鑰,更新你 App 的機密,重新發布,然後刪除舊金鑰。只刪除訊息或提交紀錄並不足夠,因為副本可能早已存在。
API 金鑰應該存放在哪裡?
存放在你主機的環境變數或機密設定中,由伺服器端程式碼在執行時讀取。它們不應該寫入原始碼檔案、提交到 Git,或出現在截圖中。
我要如何判斷我的網站是否暴露了 API 金鑰?
開啟你的正式網站,在瀏覽器的開發人員工具中檢視頁面原始碼與 JavaScript 檔案,並搜尋金鑰的開頭字元。如果找到了,就代表已經外洩,應該移到伺服器端並進行輪替。