iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0
Build on Google AI

從 Vibe Coding 到 Production:用 Google AI 打造上線守門員系列 第 9

Day 9|別把 Secret 推上 GitHub:正式環境的密鑰管理入門

  • 分享至 

  • xImage
  •  

Day 6,我們使用 GEMINI_API_KEY 呼叫 Gemini。當時只在 Terminal 設定環境變數,沒有把金鑰寫進程式。

為什麼要多做這一步?

因為前端程式會交給使用者,Git Commit 會留在歷史紀錄,Log 也可能被集中保存。Secret 只要進入其中一個地方,就很難控制誰已經看過或複製它。

今天會用一組假金鑰做實驗。我們要確認兩件事:

  1. 金鑰寫進前端後,打包工具能不能把它藏起來?
  2. 程式從環境變數讀取金鑰,是否能避免把值寫進 Repository?

什麼資料算 Secret?

Secret 是可以代表系統或身分執行敏感操作的憑證。

常見例子包含:

  • API Key
  • Access Token
  • Session Secret
  • Database Password
  • Private Key
  • Service Account Credential
  • Webhook Signing Secret

判斷重點不是名稱,而是取得這個值的人可以做什麼。

如果某個值只能識別公開專案,卻不能授權敏感操作,它不一定是 Secret。如果某個值可以呼叫付費 API、讀取私人資料或代表服務帳號,它就必須受到保護。

Firebase API Key 與 Gemini API Key 不一樣

這兩種 Key 都來自 Google 服務,但用途不同。

Key 主要用途 能否放在瀏覽器
Firebase Web API Key 識別 Firebase Project,協助路由請求與計算配額 可以,但仍應限制可用 API
Gemini API Key 驗證 Gemini API 請求並使用專案配額 正式環境不能放在 Client

Firebase Web API Key 不負責保護 Firestore 資料。Firestore 依靠 Authentication、Security Rules 與 App Check 等控制措施。

Gemini API Key 則可以消耗 API 配額,也可能產生費用。Google 官方文件明確要求正式環境不要把 Gemini API Key 寫進 Web 或 Mobile Client。

同樣叫做 API Key,不代表兩者具有相同的安全性質。

實驗:把假 Gemini Key 寫進前端

今天的實驗放在:

demo-app/secret-demo/
├── index.html
├── client.js
└── check-bundle.js

client.js 包含一組不能使用的假金鑰:

const GEMINI_API_KEY = "DEMO_ONLY_KEY_DO_NOT_USE";

document.querySelector("#status").textContent =
  `Client received a key with ${GEMINI_API_KEY.length} characters.`;

假設開發者認為變數沒有顯示在畫面上,使用者就看不到金鑰。

但瀏覽器必須先下載 JavaScript,才能執行這段程式。只要金鑰存在於 Client Source,使用者就能讀取它。

執行前端打包

進入 Demo:

cd /media/mickey/777/ithome/demo-app

執行:

npm run secret:demo

這個指令會先使用 Vite 建置 secret-demo,再搜尋產生的瀏覽器 Bundle。

實際結果如下:

Source contains demo key:        YES
Browser bundle contains key:     YES
Git ignores local .env files:    YES
Reviewer reads environment key:  YES
Reviewer contains demo key value: NO

Vite 會壓縮程式並改寫變數名稱,但假金鑰仍然存在於 Bundle。壓縮不是加密,也不是存取控制。

放進前端環境變數也沒有用

有些前端框架允許使用 .env

VITE_GEMINI_API_KEY=DEMO_ONLY_KEY_DO_NOT_USE

.env 可以避免開發者直接把值寫在 JavaScript,也能搭配 .gitignore 避免提交本機設定。

但 Vite 會把 VITE_ 開頭的變數注入 Client Bundle。只要前端程式使用這個變數,打包結果仍會包含金鑰。

因此:

.env 可以降低誤傳到 Git 的機會,卻不能讓瀏覽器中的 Secret 保密。

正式產品應由後端呼叫 Gemini。瀏覽器只呼叫自己的 API,不直接取得 Gemini API Key。

本機開發如何使用 Gemini API Key?

Day 6 的 Reviewer 從環境變數讀取金鑰:

if (!process.env.GEMINI_API_KEY) {
  throw new Error(
    "GEMINI_API_KEY is required. Export it before running the review."
  );
}

本機執行前,先在目前 Shell 設定:

export GEMINI_API_KEY="你的 Gemini API Key"

再執行:

npm run review:gemini -- firestore.rules

程式只包含環境變數名稱,不包含真正的值。

目前 .gitignore 也排除了:

.env
.env.*
!.env.example

.env.example 只能放變數名稱與明確的 Placeholder:

GEMINI_API_KEY=replace-with-your-api-key
GEMINI_MODEL=gemini-3.7-flash

不要把真正的 Key 貼進範例檔。

環境變數不是正式環境的終點

環境變數適合本機開發,但正式環境還要考慮更多風險。

Debug Endpoint、錯誤報告或第三方套件可能記錄 Process Environment。部署設定也可能讓不必要的人員讀取變數。

Google Cloud Secret Manager 使用 IAM 控制 Secret 存取,也能記錄存取事件與管理版本。Google 建議正式服務直接透過 Secret Manager API 或受支援的平台整合取得 Secret。

正式環境的基本流程如下:

Developer
   │
   └── 不取得正式 Secret

Production Service Identity
   │
   ├── 透過 IAM 取得指定 Secret
   └── 呼叫 Gemini API

Browser
   │
   └── 只呼叫自己的 Backend API

服務身分只應取得目前服務需要的 Secret。不要讓所有開發者、所有環境或所有服務共用同一把 Key。

Gemini API Key 正在改用 Auth Key

Google 目前正把 Gemini API 從 Standard API Key 遷移到綁定 Service Account 的 Authorization Key。

官方文件指出:

  • Google AI Studio 新建立的 Key 預設為 Auth Key。
  • Auth Key 會綁定 Google Cloud Service Account。
  • Auth Key 預設限制為 Generative Language API。
  • Gemini API 預計在 2026 年 9 月停止接受 Standard Key。

如果你在 2026 年 9 月前建立過 Standard Key,應查看 Google AI Studio 與官方遷移說明,確認 Key 類型與限制。

Auth Key 改善身分與權限控制,但它仍然是 Secret。開發者不能把它放進 Git 或前端。

推上 GitHub 後再刪除就安全了嗎?

不安全。

刪除目前版本中的檔案,不會自動讓舊 Commit 消失。Fork、Clone、CI Artifact、Cache 與其他開發者的電腦也可能保留副本。

GitHub Secret Scanning 會掃描 Git History 與其他 Repository 內容,尋找已知格式的憑證。偵測工具可以縮短發現時間,但不能保證 Secret 從未被讀取。

因此,Secret 一旦進入 Git,就應先假設它已經外洩。

正確順序是:

  1. 建立替代 Key。
  2. 更新服務並確認新 Key 可以使用。
  3. 停用或撤銷舊 Key。
  4. 檢查 API 使用量、帳務與存取紀錄。
  5. 再決定是否清理 Git History。

只刪除檔案,卻繼續使用原本的 Key,沒有消除風險。

提交前可以做哪些檢查?

先搜尋常見的 Secret 名稱:

rg -n \
  '(API_KEY|TOKEN|SECRET|PASSWORD|PRIVATE_KEY)' \
  --glob '!node_modules/**' \
  --glob '!dist/**'

這個指令會產生誤報,因為程式本來就可能使用 GEMINI_API_KEY 這類環境變數名稱。檢查者還要確認程式保存的是變數名稱、Placeholder,還是真正的憑證值。

提交前也應檢查 Staged Diff:

git diff --cached

Repository 建立後,還可以啟用 GitHub Secret Scanning。公開 Repository 會自動獲得 Secret Scanning;組織的 Private 或 Internal Repository 則取決於方案與 GitHub Secret Protection 設定。

Production Readiness Agent 要檢查什麼?

Agent 不應只搜尋看起來像 Key 的字串。它還要確認 Secret 如何產生、保存、傳遞與撤銷。

檢查範圍至少包含:

  1. 原始碼是否包含硬編碼憑證。
  2. 前端環境變數是否被打包進 Client。
  3. .env、憑證檔與本機設定是否被 Git 忽略。
  4. CI/CD 是否把 Secret 印到 Log。
  5. Docker Image 或 Build Artifact 是否包含 Secret。
  6. 正式服務是否透過受控身分取得 Secret。
  7. Secret 是否具備輪替、撤銷與使用量監控流程。

Agent 回報時不能印出完整 Secret。它只需要提供:

問題:Gemini API Key 被打包進瀏覽器 JavaScript
位置:secret-demo/client.js
證據:Client Source 宣告 GEMINI_API_KEY 常數
驗證:建置後的 Bundle 仍包含相同 Marker
影響:使用者可以擷取 Key 並消耗 Gemini API 配額
修正:由 Backend 呼叫 Gemini,Client 不取得 Key

如果需要識別不同 Secret,可以記錄遮罩值、Hash 或 Provider 提供的 Key ID。報告不應複製完整憑證。

今天的結論

Secret 不會因為變數名稱改變、程式被壓縮或檔案藏在 .env 就自動安全。

今天的前端打包實驗證明:Client 使用的值會進入使用者可以下載的 Bundle。

本機開發可以先使用環境變數。正式環境應使用 Secret Manager、IAM 與服務身分控制存取。Secret 如果進入 Git,則要立即輪替與撤銷,不能只刪除檔案。

明天,我們會檢查使用者輸入。即使系統沒有洩漏 Secret,未驗證的輸入仍可能造成 Injection 與惡意輸出。

參考資料


上一篇
Day 8|API、錯誤訊息與 Log:個人資料是如何不小心外洩的?
下一篇
Day 10|輸入永遠不可信:Injection、驗證與安全輸出
系列文
從 Vibe Coding 到 Production:用 Google AI 打造上線守門員10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言