誰的 AI API key 「又」外洩了!?

2026-06-05 · 3,195 字 · 7 分鐘

最近在整理苦勞德報的時候,讀到 r/OpenAI 上一篇很黑色幽默的貼文:有人不小心把自己的 API key 洩漏出去,然後就眼睜睜看著它在幾分鐘內被陌生 bot 撿走、把設好的 spending limit 整個燒光。更荒謬的是偷 key 的人拿它來幹的事——有個中國 bot 拿去問基本數學題,有個直接丟「You are now Claude Code」的 prompt、把偷來的 key 偽裝成 Claude Code 在賣,而多數請求其實只是在跑廣告文案這種雜活。樓主全程很淡定,最後還自嘲一句:「他們不會再用這把了,得等我再洩一把。」

讀完當下,我的第一反應跟留言區大多數人一樣:「啊就小心點、別把 key 洩出去不就好了。」其實——當你的 API key 公諸於世,到它成為某種公共財,只要幾分鐘。

鄉民的反應,成了一份科普教材

這串的留言區,讀起來意外像在上一堂輕鬆的資安課。有位網友把 scraper 的運作講得很清楚:這類掃描器對 GitHub commits、Pastebin 這些地方近乎即時地掃,從你的 key 曝光到第一次被盜用,往往只要個位數分鐘。也有人把「撿 key 的到底是誰」拆得很生活化——它們不是同一種人:有把 key 轉賣給自己客戶的 API reseller、有拿去跑測試的 bot、也有純粹想把你額度燒光的人。那句「You are now Claude Code」,就是 reseller 撿到 key、假裝在賣 premium Claude 模型的話術。還有人用一個很好記的比喻收尾:這些 scraper 24 小時在掃 GitHub,你得從第一天就「把 API key 當放射性物質處理」,否則等於在幫別人付帳單——形同跟那些 bot 喊一句:這攤我請了,儘量吃、別客氣。

「小心別洩漏」是對的,但它注定有破口

把 key 藏好、別 commit 上去、別貼進前端——這些當然都該做。問題是,「小心」是一條靠人不犯錯來維持的防線,而你面對的是一張 24 小時、近乎即時的自動掃描網。人類發現「啊我洩漏了」往往是幾小時甚至幾天後的事,scraper 撿走它只要幾分鐘。這條防線你不是守不住,是它的反應時間天生就輸。

所以我的「亂回」是這樣:防洩漏只是第一道防線,而且是注定會有破口的那一道。把全部力氣壓在「我絕對不會洩漏」上,等於賭自己永遠不犯錯。真正能靠設計贏的,是洩漏之後的事。

順帶一提,留言區有人吐槽:大家把身分證字號、基因組、銀行密碼都丟給 ChatGPT 了,卻為了一把 API key 緊張兮兮。這個對比很好笑,但其實反了——API key 是 bearer credential,撿到的人不需要再驗證身分就能直接花你的錢,而且是按量計費。它「撿到即可用、直接燒錢」的性質跟一般個資不一樣——也正因如此,前面那位鄉民「把 API key 當放射性物質」的比喻,才不是誇張,是剛剛好。

換個問法:假設它一定會洩

與其問「怎麼不洩漏」,我改成對手上每一把 key 問三個問題:

  1. 爆炸半徑:這把 key 一旦外洩,最多能燒多少錢、能碰到哪些資料、能造成多大破壞?
  2. 偵測延遲:從外洩到我發現,中間有多久?拿「個位數分鐘」當對照尺,多數人的答案都太長。
  3. 止血速度:發現之後,我多快能讓它失效?rotate 或 revoke 的摩擦有多大?

後面這兩題,其實最容易破功。偵測延遲這關,老實說工具還不夠成熟——現階段 provider 的 usage API 對即時監控的支援都還很有限——有的甚至連 API 都還沒提供,真要抓異常,搞不好得自己寫支爬蟲定時去對帳;但退一步,至少把 alert notification 開起來,讓用量爆衝的時候 email 會主動敲你一下。止血速度則是個摸著良心的問題:你有多久沒去 rotate、或把那些早就不用的 key 清掉了?能不能秒撤銷是一回事,記不記得去撤、平常有沒有在清,又是另一回事。

同一把 key,洩漏的後果可以天差地別。一把權限受限、額度壓低、有用量告警、能秒撤銷的 key,洩漏了頂多是一場虛驚;一把擁有完整權限、沒有上限、沒人監控的 key,藏得再好都是一顆定時炸彈。差別不在你藏得好不好,在你當初設計它的時候,有沒有先假設它會洩。

最該先做的一件事:把 spend limit 改小

如果只能做一件事,我會選這個——最容易、最快生效,偏偏大多數人從沒去動過。兩家給的預設上限通常都遠大於新手的真實用量,等於把爆炸半徑開得太大。

要做的其實很單純:至少去看一眼目前的上限是多少,把它調低、貼近你實際會用的量,順手也把用量的 email 告警設起來。這樣就算 key 被撿走,最多只燒到這個數字,爆量時信箱還會先敲你一下。

設定位置兩家官方文件都寫得很清楚:Anthropic 在 Console 的 Limits 頁 設 spend limit——org 與 workspace 兩層都能設(workspace 上限不能高於 org),並可一併開 email 告警;OpenAI 在 project 的 Monthly budget 與 Notification threshold

至於其餘那一整套——key 不要進 git、定期輪替、用 secret manager 之類——網路上已經有非常多現成的 best practice,我就不再一條條重複。

由經驗者的角度來看

先把「是不是 AI 在用的 API key」這件事擺一邊。對比較資深的開發者來說,碰到要用某個服務的 key,第一個會想的往往不是「key 要怎麼保管」,而是更前面一步——這件事,有沒有根本不需要 key 的做法?

最常見的例子就是雲端虛擬機。它們幾乎都附一個預設的權限身份(GCP 的 default service account、AWS 的 IAM role),你只要在機器上指定它,之後程式呼叫 API 時就會自動綁上這個身份、以它的權限執行。細節上它其實還是會拿到一組 API key,只是效期很短——好處是它自動 rotation,而且你打包好的專案根本不用把 key 包進去,甚至連「用環境變數指定代理身份」這一步都省了。只要你不自己寫一個 service endpoint 把這把短效期 key 漏出去,它真的極難外洩。

也許你會想:那是雲端大廠的基礎建設,跟我手上這把 AI API key 有什麼關係?關係比我原本以為的還大——這點後面會回來講。先記住一個現在就成立的重點:其實不必把 API key 直接打包進程式裡。

把 key 抽出去的做法,前面附註也提過 secret manager,各家雲都有相近的產品;不想用雲的,也可以自己在內網架一套 HashiCorp Vault。重點是觀念的轉換——包進程式裡的,應該是「取得秘密的方法」,而不是「秘密」本身。

那如果你只是本機在用呢?放進系統的憑證庫就好,macOS 有 Keychain、Windows 有 Credential Manager,讓程式自己去取。至於 .env,老實說只適合放那些「漏了也沒什麼殺傷力」的東西。

如果我還是想把秘密放進去呢?

我知道人總有不得已的時候。如果你還是想用 .env、或非得把東西打包進程式不可,有兩個主要的思路。

第一,一樣別讓它直接躺在 source code 或打包好的成品裡。真的避不掉,就把它推遲到打包的「工序」才塞進去——用 CI/CD 提供的 secret 機制保管真正的值,打包時再替換掉一份假的 .env

第二,.env 其實也不建議用「一個變數」就裝完。把它拆散成幾個看不出原貌的片段、最後在程式裡再組回來——這樣一來,大概就只剩 memory leak 那一類的攻擊還有機會打中你了。

工具上,本機開發可以用 direnv:一進到專案目錄就自動載入 .envrc、離開就卸載。比較講究的用法,是讓 .envrc 裡放「取秘密的指令」而不是秘密本身——例如呼叫 1Password CLI、pass、或系統 keychain 把值臨時撈進環境變數。這樣即使 .envrc 被看到,露出來的也只是「怎麼取」、不是「取什麼」,正好呼應前面那句:要包進去的,是取得秘密的方法。

還有一個這年頭特別容易漏的點:.envrc.env 這類檔案,記得同時寫進 .gitignore 和你 AI 工具的忽略清單(像 Cursor 的 .cursorignore,各家叫法不一)。前者擋的是 commit 進 repo,後者擋的是 AI 助手把它整個讀進 context——少了第二道,等於一手把秘密藏好、另一手又親手餵給工具。

能不直接包進去,當然最好。把「打包程式」和「把新秘密部署到執行環境」拆成兩件事,到「執行期」最後才合併——這是不得已時的最後一招。

Workload Identity Federation

在我懷疑是否只有原始的 API Key 管理機制時,順手查了一下,OpenAI(5 月 26 日)和 Anthropic(同一週前後)幾乎同時把 Workload Identity Federation(WIF)端上來了(文件:OpenAIAnthropic)。它就是「不必持有長期 key」的那條路:你的 workload 拿本來就有的 OIDC 身份去換一個短效期 token,全程不必落地一把 sk- key——用 Anthropic 文件的說法,「沒有任何 static secret 要 mint、保管、輪替或外洩」。

最好懂的例子是 GitHub Actions:你的 CI 不必再存一把長期 key,workflow 跑的時候 GitHub 會幫它簽一個 OIDC token,拿去跟供應商換一個短效期 token 來用,用完即失效,repo 裡什麼長期密鑰都不留。AWS、GCP、Kubernetes 這些環境也是同一套;npm、PyPI 的 trusted publisher 早就這樣發套件了——AI 供應商只是終於接上這個業界跑很久的模式。

所以方向整個翻過來了。本來想說供應商原始、該被要求改進,結果該動的不是他們——東西已經在那——是使用者的預設習慣:申請就送你一把長期 sk- key,範例清一色用它,這波 vibe coding 進來的人多半只看過它,根本不知道 WIF 是個選項。

要說清楚的是,WIF 是給 workload 用的(雲端 VM、Kubernetes、CI/CD、agent runtime)。本文開頭那種在自己機器上手滑外洩的情境,多半還是會用一把 key,那就回到前面:收進 keychain、用 direnv、把 spend limit 壓低。但只要東西是跑在伺服器或 CI 上,現在真的可以不必再抱著一把長期 key。

這篇是從當天苦勞德報借題發揮的;原始貼文是 r/OpenAI 的〈I accidentally leaked an API key and a bot found it〉。