Vibe Coder
API 安全與 Secret 管理:別讓一組 API Key 拖垮帳單
API Key 絕對不能寫死在程式碼或放進前端,正確做法是存在環境變數,正式環境用平台的 Secrets 功能。JWT 要設過期時間並用至少 256 位元的隨機 Secret。如果 Key 不小心外洩,第一步永遠是立刻在服務端撤銷,再處理 git history 與異常使用紀錄。
API 安全與 Secret 管理:別讓一組 API Key 拖垮帳單
有人專門在 GitHub 上掃描公開 repo 裡的 API Key,找到後幾秒內就開始盜用,OpenAI Key 洩漏後帳單暴增的故事並不少見。AI 生成的範例程式碼常直接寫 api_key="sk-xxx",那只是示範用,絕對不能照搬到真實專案。
這篇帶你看懂 API Key 該存在哪裡、.env 有哪些常見地雷、JWT 怎麼設計才安全,以及最重要的:一旦 Key 洩漏,該怎麼在最短時間內止血。
你將學到什麼
Key 該存在哪裡
環境變數、平台 Secrets、Secret Manager 的分工。
.env 的地雷
.gitignore 一定要加、絕不能寫死在程式碼裡。
JWT 怎麼設計才安全
過期時間、Secret 強度、正確的產生與驗證方式。
授權不能只靠前端
resource owner 驗證,防止 A 看到 B 的資料。
API Key 的正確存放方式
| 方式 | 安全性 | 適合 |
|---|---|---|
| 環境變數(.env) | 本機開發用,.env 加進 .gitignore | 本機開發 |
| 平台 Secrets | Railway、Render、Vercel 的 Environment Variables | 正式環境部署 |
| Secret Manager | AWS Secrets Manager、GCP Secret Manager | 企業級,有稽核 |
| 寫死在程式碼 | 最不安全 | 永遠不要 |
| 存在前端程式碼 | 瀏覽器可以看到 | 永遠不要 |
環境變數與 .env 的注意事項
# 這個檔案要加到 .gitignore,永遠不要 commit
.env
.env.local
.env.production
# 可以 commit 的:範本(不含真實值)
.env.example # 內容只有 KEY_NAME= 沒有值
import os
from dotenv import load_dotenv
load_dotenv() # 讀取 .env 檔案
# 用 os.getenv 讀取,不要寫死
API_KEY = os.getenv("OPENAI_API_KEY")
if not API_KEY:
raise ValueError("OPENAI_API_KEY 環境變數未設定")
已經不小心 commit 了 Key 怎麼辦① 立刻撤銷那個 Key(在各平台的設定裡)② 產生新的 Key ③ 用 git filter-repo 或 BFG Repo Cleaner 清除 git history ④ 確認有沒有異常使用記錄。步驟①是最重要的,先撤銷再處理 history。
JWT 安全設計
JWT 是常見的 API 認證機制,但有幾個安全要點容易被忽略。
from datetime import datetime, timedelta
import jwt, os
SECRET = os.getenv("JWT_SECRET") # 至少 256 位元的隨機字串
def create_token(user_id: str) -> str:
payload = {
"sub": user_id,
"exp": datetime.utcnow() + timedelta(hours=1), # 1 小時後過期
"iat": datetime.utcnow(), # 發行時間
}
return jwt.encode(payload, SECRET, algorithm="HS256")
def verify_token(token: str) -> dict:
return jwt.decode(token, SECRET, algorithms=["HS256"])
JWT Secret 的強度JWT Secret 至少要 256 位元(32 bytes),用 openssl rand -hex 32 或 secrets.token_hex(32) 生成,不要用「secret」或「mysecret」這種弱字串。
API 授權:誰能做什麼
認證(Authentication)確認你是誰,授權(Authorization)確認你能做什麼,兩者都要做。
| 常見授權問題 | 後果 | 解法 |
|---|---|---|
| 沒有驗證 resource owner | 使用者 A 能讀取使用者 B 的資料 | 查詢時帶入 current_user.id 過濾 |
| 前端隱藏按鈕就算授權 | 直接呼叫 API 就能繞過 | 後端每個 endpoint 都要驗證權限 |
| Admin 功能沒有角色檢查 | 一般使用者能呼叫管理員 API | 加 require_admin 的 middleware |
async def get_my_weather_history(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
# 只取目前使用者的資料,不是全部
return db.query(WeatherHistory).filter(
WeatherHistory.user_id == current_user.id
).all()
Secret 洩漏的緊急處理
- 立刻撤銷:在各服務的設定頁面撤銷洩漏的 Key,這是最優先的事。
- 產生新的 Key:撤銷後立刻產生新 Key,更新所有用到的地方。
- 檢查異常使用:查看各服務的 usage log,確認有沒有未授權的使用。
- 清除 git history:用 git filter-repo 移除 commit 裡的 Secret,然後 force push。
延伸學習
寫給升國一的你的筆記術
寫給剛升上國中的你:筆記不是寫給老師看的,是寫給考前的自己看的。18 章 85 課圖文,從「為什麼要寫」講到七科各自怎麼記,附 78 份可以印出來寫的練習單,以及 80 課家長專區與 34 張三年筆記養成路徑圖。沒有閱讀期限,國一買、國三還在。
NT$ 3,599
HE201|Harness Engineering System Design(6 小時)
六小時的實作課:從 Blueprint 走到可以跑的規格,再用 No-code、n8n 低程式碼與程式碼三條路各做一次同一個 harness,最後處理可靠度——重試、錯誤處理、人工覆核。7 章 54 課,含常見坑與排錯、Capstone 實作,附學員講義 PDF。
NT$ 5,999
常見問答
API Key 可以存在前端程式碼嗎?
絕對不行。前端程式碼在瀏覽器裡可以被任何人看到,Key 只要出現在前端就等於公開了。所有需要 Key 的呼叫都應該經過你自己的後端。
已經不小心 commit 了 Key 怎麼辦?
第一步永遠是立刻撤銷那個 Key,然後產生新 Key,接著用 git filter-repo 或 BFG Repo Cleaner 清除 git history,最後確認有沒有異常使用記錄。撤銷是最重要的一步,先撤銷再處理 history。
JWT 和一般的 Session 有什麼不同,安全設計要注意什麼?
JWT 是自帶資訊的加密字串,重點是要設定合理的過期時間(例如 1 小時),Secret 至少要 256 位元的隨機字串,不要用像 secret 這種弱字串。
什麼是 IDOR?
IDOR(Insecure Direct Object Reference)是指 API 沒有驗證資源的擁有者,例如 GET /api/history/123 只要沒確認 123 是不是你的資料,任何登入使用者都能看到別人的資料,這是很常見卻很容易被忽略的授權漏洞。

