作者分析

被偷三次之後,我們決定換一種方式放鑰匙

後門 Lambda、Owner 金鑰 15 天、356 天挖礦、單日 $3,901 的 Gemini 帳單——四次損失的共同點不是漏洞,是明文憑證散落各處。這篇是作者分析:為什麼我們推薦開發者把憑證交給 1Password Developer Security 這類 secrets manager,以及它擋得住什麼、擋不住什麼。

30 秒看懂
  • 我們四次損失(後門 Lambda、Owner 金鑰 15 天、356 天挖礦、單日 $3,901 的 Gemini 帳單)沒有一次是系統被打穿:每一次都是一個明文憑證換了持有人。
  • 1Password Developer Security 把憑證集中進保管庫,程式用 op:// 參照在執行時注入、SSH 私鑰用 Touch ID 授權、機器與 AI agent 走可撤銷的 service account——磁碟上不再留明文。
  • 它不是護身符:注入進程式的憑證仍可能被讀走,雲端內部能用 IAM Role 的地方也應該用 IAM Role。我們推薦它的理由是盤點與生命週期,不是零風險。

我們不是被打穿的,是鑰匙被撿走的

把這個站寫過的四次損失排在一起看,形狀出奇一致。2025 年 7 月,沒用過的區域裡長出兩支會發 IAM 管理員帳號的 Lambda;2026 年 8 月,一把 2020 年建的服務帳戶金鑰在外面流了 15 天;同年 9 月,一台主機被挖礦挖了 356 天;10 月,一把休眠一年的 Gemini API key 單日刷出 $3,901。四起事件,沒有一起用到值得寫論文的漏洞。每一起的起點,都是一個明文字串換了持有人。

先講清楚:這篇不是業配。我們沒有收 1Password 任何費用或好處,推薦的理由全部來自我們自己的帳單。這篇要回答的只有一件事——為什麼我們認為小團隊開發者該把憑證交給 secrets manager 管,以及這個決定擋得住什麼、擋不住什麼。

證據先擺上來。下面這張表是四起事件裡具代表性的四把憑證,每一把的細節都在對應的防暴筆記裡審過:

leaked credentials這次外洩了什麼:服務、用途、存在形式
服務憑證類型用途存在形式放在哪權限範圍狀態
GCP:Service Account(IAM 服務帳戶)Google Service KEY JSON(長期私鑰,無到期日)訊息機器人讀寫試算表、上傳照片JSON 檔明文;在部署平台則是整段 JSON 塞進環境變數兩個 repo 的 git 歷史+部署平台環境變數+開發者本機(詳見 INC-2026-0827)roles/owner,專案層級全權限2020-09 建立,2026-09-13 刪除
AI 服務供應商 API(語音轉文字與改寫)長期有效的 API key × 2排程流程呼叫轉逐字稿與改寫原始碼常數:明文字串寫死在排程腳本裡受害主機的腳本目錄,root 可讀(詳見 INC-2026-0915)該供應商帳號的 API 用量與帳單事件後視為外洩並撤銷
Google Gemini APIAPI key(AIza 開頭格式,已遮蔽)一個最後沒上架的 iOS app 的開發用金鑰明文字串,開發期存在於程式碼與設定中實際外洩位置至今未確認(詳見 DISPATCH-2026-1003)產生時預設不綁 app、不綁 API、無用量上限2026-10-03 已作廢
最初被用來建立後門 Lambda 的 AWS 憑證長期存取金鑰或不經 MFA 換到的暫時憑證攻擊者的初始存取格式無法確認未知——留存的事件摘要不足以指認是哪一把(詳見 INC-2025-0717)足以建立 Lambda、角色與 API Gateway處置時全數輪替,但無法指認
憑證本身已遮蔽或失效;這裡只說明它是哪個服務、拿來做什麼、以什麼形式存放,讓你能對照自己的環境。

表裡最該看的是最後一列:事件結束一年多了,我們連「被撿走的是哪一把」都說不出來。說不出來的原因很簡單——當時根本沒有一張「我們總共有哪些鑰匙」的清單。

問題不是沒有保險箱,是鑰匙從來不在保險箱裡

四把憑證的死法各不相同,出生卻一模一樣:某個開發當下,一個明文字串被貼進 .env、寫進腳本、commit 進 repo,或塞進部署平台的環境變數欄位。從那一刻起它就開始複製自己——本機一份、git 歷史一份、平台一份、同事的機器可能再一份。沒有人記錄它存在幾處,沒有人負責它的退場,輪替的時候永遠會漏掉其中一份。這個狀態有個正式名字,叫 secrets sprawl(憑證蔓延);MITRE 把對應的攻擊手法編成 T1552 Unsecured Credentials——翻成白話是「不用偷,用撿的」。

.env 檔案值得單獨點名。它常被當成「把憑證移出程式碼」的最佳實務,但對撿鑰匙的人來說,.env 是把機密整理得更好偷:固定檔名、固定格式、一個檔案集齊一個專案的所有權限。我們的 Owner 金鑰事件裡,攻擊者從部署平台拿到的就是這樣一整組環境變數——資料庫密碼、AWS 金鑰、服務帳戶 JSON,一次到位。

所以我們要解的不是「怎麼讓字串不外洩」,是「怎麼讓磁碟上根本沒有字串」。

1Password Developer Security 在賣什麼

一句白話:它把密碼管理器的保管庫延伸到開發流程裡,讓憑證平常只存在於加密保管庫中,程式要用的那一刻才解析注入,磁碟上留下的只是一個指向保管庫的參照字串。參照本身洩漏了也沒有用——它不是憑證,只是地址。

到這裡,其實已經足夠理解我們推薦它的核心理由。如果你想先知道它擋不住什麼,可以直接往「它擋不住什麼」繼續閱讀。如果你想看各個元件實際長什麼樣子,下面進入技術細節。

深入閱讀六個元件各自解什麼問題以官方開發者文件為準,連結都在 sources

CLI 與 op:// 參照:.env 裡不再放真值,放參照。程式啟動改用 op run 包一層,1Password 在執行時解析參照、注入環境變數,行程結束即消失:

# .env 裡存的是地址,不是鑰匙
DATABASE_PASSWORD="op://Development/MySQL/password"

# 啟動時才解析注入
op run --env-file=.env -- node server.js

SSH Agent:私鑰存在保管庫,SSH 連線與 Git 簽署時由 agent 代答,每次使用在 macOS 上用 Touch ID 授權。~/.ssh 底下不再躺著複製過不知幾台機器的 id_rsa。

Environments:團隊版功能,讓專案成員共用同一組開發環境機密,不需要互傳 .env 檔,也不需要在磁碟留明文。

Service Accounts:給機器用的身分。排程、CI、自動化工具各拿一個只能讀特定保管庫的 token,可以單獨撤銷、有速率限制、有存取紀錄——取代「大家共用一把高權限金鑰」。

SDK(JavaScript/Python/Go):應用程式在執行階段直接向保管庫取值,程式碼與設定檔全程不出現真值。

Developer Watchtower 與 Credential Broker:前者掃描團隊裝置上未受管的憑證,告訴你蔓延集中在哪裡、該找誰收斂;後者給 AI agent 有時效、受控的憑證存取——agent 要用的權限由仲介發放,不是把 key 貼進提示詞或設定檔。

對著我們自己的四起事件打分數

推薦一個工具最誠實的方式,是回頭問:如果當時就在用,四起事件會怎樣?這一段全部是推論,不是證明——歷史沒有對照組。

Owner 金鑰那把 KEY JSON,當年是以檔案形式進了 git 歷史、以明文塞進部署平台變數。如果它只存在於保管庫、repo 與平台上只有 op:// 參照,那兩條已證實的外洩路徑都不成立。挖礦事件裡寫死在腳本的兩把 API key 同理:root 翻遍腳本目錄,拿到的會是地址而不是鑰匙。這兩起,初始路徑有很高機率被截斷。

Gemini key 那把我們不敢這樣講。洩漏點到今天還是 gap,說「在保管庫裡就不會出事」是把願望當證據。它真正對應的功能是另一個:保管庫強迫每把憑證有名字、有位置、有建立時間,一把「給沒上架的 app 用、休眠一年」的 key 在盤點裡會刺眼得多——但「會不會真的有人去看盤點」是流程問題,工具替代不了。後門 Lambda 事件也一樣:連是哪把憑證被偷都不知道的案子,任何工具都只能說「至少以後你列得出清單」。

所以打完分數,我們推薦它的理由其實不是「防偷」,是兩個更樸素的字:盤點與生命週期。每把鑰匙有地方住、有人負責、查得到還活著沒有——我們四起事件裡最貴的共同缺口,就是這個。

它擋不住什麼

這一節是整篇最重要的部分,因為 secrets manager 最危險的用法是把它當護身符。

第一,憑證注入進執行中的程式之後,保護就結束了。記憶體裡的值可以被同一台機器上的惡意程式讀走、被過度詳細的 log 印出來、被一個有執行權限的 AI agent 原樣轉述出去。356 天那台主機如果重來一次,攻擊者已經是 root 的狀態下,op run 注入的值一樣躲不掉。工具縮小的是「靜態攤在磁碟上」的暴露面,不是執行階段的暴露面。

第二,能用平台原生短期憑證的地方,輪不到它。AWS Lambda 掛 IAM Role、GCP 服務用 attached service account,這些短期憑證自動輪替、不落地,比任何保管庫方案都好。為了統一用 1Password 而替雲端工作負載重新發長期金鑰,是倒退——AWS 自己的最佳做法文件就把「優先用暫時憑證」寫在最前面。

第三,它不解決權限過大。Owner 金鑰事件的根因有兩層:金鑰以明文外流是一層,一個只寫試算表的 bot 拿著專案 Owner 是另一層。保管庫只管第一層,第二層還是得靠最小權限。

第四,集中本身是新的風險面。所有鑰匙住進同一個保管庫,代表那個帳號成為最高價值目標,master password 與 Secret Key 的保管、團隊成員的裝置安全,變成新的單點。正式環境的高頻服務也不適合每個請求都去保管庫取值——官方自己對 service account 設了速率限制,架構上該取一次、活在行程記憶體裡。

誠實地說完這四條,推薦依然成立:因為我們損失的四次,沒有一次是輸在這四條上,全部輸在更前面的那一步——明文躺在磁碟上,而且沒有人知道它在那裡。

如果今天開始導入,順序是這樣

當天能做的是 SSH 私鑰:把 ~/.ssh 底下的私鑰收進保管庫、開 SSH Agent、刪掉散落的 PEM 檔,GitHub、Git 主機、跳板機的連線從此走 Touch ID。這一步不動任何程式碼,風險最低,立刻少掉一整類「私鑰複製過幾台機器」的問題。

一週內做 CLI:挑一個本機專案,把 .env 的真值搬進保管庫、原地換成 op:// 參照、啟動指令包上 op run。跑順了再往其他專案複製,並依開發、測試、正式分保管庫,權限分開給。

一個月內收自動化:排程、CI、工作流程工具各發一個最小權限的 service account,淘汰共用的高權限 token。最後才是 AI agent——Cursor、MCP 這類會碰憑證的工具,改走 service account 或 Credential Broker,讓 agent 用得到權限、看不到鑰匙,並定期輪替。雲端工作負載維持 IAM Role,不要回頭發長期金鑰。

這些主張的證據等級

這是觀點文,觀點更要標清楚哪些有據、哪些是推論、哪些還不知道。

這篇提到的項目要花多少錢

這張表左邊是保險的牌價,最下面兩列是我們已經繳過的學費。對比不在金額大小,在順序——學費都是在沒買保險的狀態下繳的。

costsecrets manager 的年費,對照我們已付過的學費
項目用量單價期間US$NT$舉證
1Password Individual(含開發者工具)1 人US$2.99/月(首年促銷,原價 $3.99)年繳一年35.881,148官方個人方案定價頁(2026-10-13)
1Password Teams Starter Pack含 10 人US$24.95/月年繳一年299.409,581官方商業方案定價頁(2026-10-13)
1Password Business每人US$8.99/人/月年繳一年(每人)107.883,452官方商業方案定價頁(2026-10-13)
Secrets Automation/Connect 伺服器附加功能未公開牌價———官方頁僅標示為 add-on,需另洽
導入人力(SSH+CLI+保管庫整理)
估
估 4–8 小時—一次性——本站估算,依導入順序一節的範圍
學費:Owner 金鑰 15 天的已證實損失異常用量—2026-08-28 → 09-12146.004,672INC-2026-0827 帳單證據(詳見該篇 Cost 表)
學費:休眠 Gemini key 單日消耗Gemini API 呼叫—2026-10-02 單日3901.00124,832GCP 費用頁截圖(詳見 DISPATCH-2026-1003)
合計(僅可證明列)4490.16143,685
匯率假設 1 USD ≈ NT$32。單價為公開牌價或帳單實付,來源:1Password 官方定價頁(2026-10-13 查閱)、本站防暴筆記與拆解的帳單證據。「舉證」欄標明每筆損失的證據來源與等級( 可證明 推論 缺口)。

兩筆學費相加是 $4,047,夠付 Teams Starter Pack 十三年。這個除法我們希望你永遠不需要自己算一次。

你可以學到什麼

站在攻擊者那一側看,開發者的機器是一座整理好的倉庫:.env 檔名固定、格式固定,git 歷史保存他刪過的每一版,部署平台的變數頁一次列齊所有權限,腳本常數連搜尋都不用就攤在那裡。他的工具鏈全是現成的,掃描、驗證、入池、轉賣,每一步都自動化。你專案做不做得起來、公司賣什麼,他從頭到尾不在乎——他在乎的只有那個字串背後接著什麼:一張信用卡、一個寄信網域、一顆能開機器的雲端帳號。讓他失業的方式不是把字串藏得更巧,是讓磁碟上根本沒有字串。

lessons本案的 6 個教訓
  1. 01
    我們四起事件沒有一起是系統被打穿,每一起都是一個明文字串換了持有人;對小團隊來說,管好字串比追新漏洞更急。
  2. 02
    .env 不是機密管理,是把機密整理得更好偷:固定檔名、固定格式、一個檔案集齊一個專案的所有權限。
  3. 03
    secrets manager 真正的價值是盤點與生命週期——每把鑰匙有地方住、有人負責、查得到還活著沒有;防偷只是副作用。
  4. 04
    憑證注入進程式之後保護就結束了:記憶體、log、有執行權的 agent 都讀得到。工具縮小暴露面,不取代最小權限。
  5. 05
    雲端內部能用 IAM Role、attached service account 這類短期憑證的地方,就不要為了統一工具回頭發長期金鑰。
  6. 06
    推薦工具要連同它擋不住的部分一起講,否則就是在賣護身符。
keywords重點學習:最需要學習的 10 個關鍵字10 個
  1. 01
    secrets sprawl(憑證蔓延)
    我們四起事件的共同根因:同一把憑證不知不覺存在五個地方,輪替永遠漏一份。
  2. 02
    op:// 參照(secret reference)
    整套方案的核心動作:磁碟上放地址、不放鑰匙,參照洩漏了也換不到權限。
  3. 03
    op run
    讓既有程式零改碼接上保管庫的那條指令:啟動時解析參照、注入環境變數、行程結束即消失。
  4. 04
    1Password SSH Agent
    私鑰不再以檔案散落,連線時 Touch ID 授權;是導入順序裡風險最低、當天能完成的第一步。
  5. 05
    Service Account(1Password)
    機器身分:排程與 CI 各拿一個只能讀特定保管庫、可單獨撤銷的 token,取代共用高權限金鑰。
  6. 06
    Credential Broker
    AI agent 用得到權限、看不到鑰匙的機制——key 不進提示詞,是 agent 時代最該盯的那一格。
  7. 07
    Developer Watchtower
    回答「我們的憑證蔓延到哪了」的盤點工具;我們後門 Lambda 案最缺的就是這張清單。
  8. 08
    IAM Role vs 長期金鑰
    雲端工作負載的正解是平台原生短期憑證;為了統一工具重發長期金鑰是倒退。
  9. 09
    休眠憑證
    沒人用不代表失效:保管庫讓「建立時間一年前、無人認領」這種 key 在盤點裡刺眼到藏不住。
  10. 10
    T1552 Unsecured Credentials
    這整篇對應的攻擊手法編號,白話是「不用偷,用撿的」;防的方法就是讓他沒得撿。
try today今天就可以來試試約 15 分鐘

全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。

  1. 找出你機器上散落的 .env(唯讀)
    find . -maxdepth 4 -name ".env*" -not -path "*/node_modules/*"
    看到什麼代表什麼:列出來的每一個檔案都是明文憑證存放點。數量比你以為的多,就是 secrets sprawl 的現場。
  2. 查 .env 有沒有進過 git 歷史(唯讀)
    git log --all --oneline -- .env .env.local
    看到什麼代表什麼:有任何輸出,代表憑證在歷史 commit 裡;就算現在已從工作目錄刪除,撿得到歷史的人就撿得到鑰匙。
  3. 掃 repo 完整歷史裡的金鑰(唯讀)
    gitleaks detect -s . --log-opts="--all"
    看到什麼代表什麼:任何命中都代表那把憑證要當成已外洩處理——repo 現在是私有的也一樣。
  4. 盤點你的 SSH 私鑰(唯讀)
    ls -la ~/.ssh
    看到什麼代表什麼:每一把 id_ 開頭的私鑰,問自己兩個問題:它複製過幾台機器?少了它哪些門打不開?答不出來的那把,就是該收進保管庫的第一把。
  5. 挑你最重要的一把 key,寫下它現在存在的所有位置(不用指令)
    看到什麼代表什麼:寫得全,你的盤點及格;寫不全,這篇的建議就是為你寫的。那張清單我們取名「key-address-book-z2q」,搬進保管庫時第一把就從它上面挑。

結尾:鑰匙該有地址

四起事件教我們的事可以壓成一句:鑰匙不可怕,沒有地址的鑰匙才可怕。一把憑證該像一筆資產——有地方住、有人負責、有建立日和退場日,要用的時候才出現,不用的時候誰也看不見。

我們自己的導入走到哪了:SSH Agent 與本機 CLI 已經在用,保管庫分環境整理中;service account 收自動化、以及 AI agent 走 Credential Broker 的實測,還在排程上。上面兩個 gap——實測行為與成效——等我們跑完會回來更新。到時候哪一格從 gap 變成 proven,照實改。

來源

分享
精選拆解直送信箱

每篇新文章一封:三點摘要、關鍵字定義、今天能做的一件事。

延伸閱讀