事件經過
一名學生用學生電子郵件地址註冊了一個雲端帳戶,並在 300 USD 的免費額度內使用。其中約 80 USD 花在小型的學習練習上,還剩下 220 USD 以上。初夏時,一枚 API key 被推送到 GitHub 上一個帳戶持有人以為是私有的程式專案裡,就這樣留在該專案保存下來的歷史紀錄中。
6 月接著來了一張 732 USD 的帳單。這筆錢沒有被收走,因為帳上登記的付款卡片早已過期,而付款失敗的通知也沒有送到帳戶持有人的手機上。8 月又來了一張超過 31,000 USD 的帳單,9 月初再累積了 21,000 USD 的費用。暑假期間,那個學生電子郵件地址沒有人在讀。
9 月,發現這枚外洩金鑰的開發者透過 GitHub 發出通知,說這枚金鑰已經公開很久,而且有其他人正在使用它。帳戶持有人打開帳戶,看到總額 55,444.78 USD,立刻撤銷了這枚金鑰。接下來的 2 天內,使用這枚金鑰的不明人士又發出超過 14,200 次使用嘗試,失敗率 100 %。
帳戶持有人聯絡了雲端服務商的計費支援、報了警,並提供使用紀錄、GitHub 連結、螢幕截圖與其他文件,說明帳上登記的卡片已經過期。案件經過審查,得到的答覆是這些費用依然有效:不取消、不變更。接著又收到通知,表示若未在 10 天內付清餘額,這筆債務將移交催收機構,並可能加上額外費用。在帳戶持有人所在的國家,平均每日收入約為 15 USD。
主要來源——S1:https://www.reddit.com/r/googlecloud/comments/1noctxi/student_hit_with_a_5544478_google_cloud_bill存檔快照
損失成因
- 一枚有效的金鑰可以毫無天花板地不斷累加帳單,而不斷長大的費用從來沒有從一個平靜的普通帳戶中被凸顯出來 一枚有效金鑰的每一次呼叫都會計費,因此損失的規模是由帳戶上的天花板、以及警告多快落到有人在看的地方所決定。在沒有任何上限生效、計費信件又寄到暑假期間沒人閱讀的信箱的情況下,總額可以用機器的速度攀升好幾個月,才被人看見。技術名稱:無支出上限的計費憑證(uncapped billable credential)
- 一枚進到程式專案保存歷史裡的金鑰持續有效了好幾個月,沒有東西撤銷它,也沒有東西提示它可被讀取 程式碼分享網站會保留專案的每一個舊版本,因此金鑰在目前檔案背後的歷史紀錄裡仍然可以被讀出來。一枚本身不會自動到期的金鑰,在有人撤銷它之前,可用程度和它被寫下的那天完全一樣,這就是為什麼這次暴露從初夏一直延續到 9 月有陌生人來信。技術名稱:版本歷史中的長效密鑰(long-lived secret in version history)
判讀
金鑰外洩是一次性的失誤;一個沒有上限的帳戶,會把它變成每天沒人注意就繼續長大的帳單。決定這次損失規模的不是那次失手,而是失手之後那幾個月無人節制的支出,以及第一個察覺異常的人是陌生人,而不是開發者本人。
自我查核
只有你能回答的
- 當你註冊並拿到免費額度時,你是不是把那筆額度當成這個帳戶最多能花的錢?曾經有任何東西告訴你並非如此嗎?
- 如果現在就有別人在使用你的某一枚金鑰,在事情變得無法挽回之前,你最多能吸收多大的一筆帳單?你曾經替這件事寫下一個數字嗎?
- 你每週真正會讀的是哪一個信箱、哪一支電話?你當初以為「錢從你帳戶流出」的消息,會送到那裡嗎?
你的 AI 可以幫你查的
只做報告,不要修改任何程式碼或設定。每一項發現都要附上檔案或主控台的參照位置;凡是從你能看到的資訊無法判定的,請明白說出來。
- 列出我擁有的每一個雲端計費帳戶。逐一report:是否設定了預算或支出上限、金額是多少、達到上限時會停止付費使用還是只發出訊息,以及計費告警與付款失敗通知會送到哪些電子郵件地址和電話號碼;並附上主控台參照位置。
- 列出我帳戶上每一枚有效的 API key,包含建立日期、最後使用時間、可以呼叫哪些付費服務、是否被限制在特定服務或特定呼叫來源,以及是否有任何各服務的用量配額。標示出任何沒有限制、也沒有到期時間的金鑰,並附上主控台參照位置。
- 搜尋我擁有的每一個 repository 的完整 commit 歷史、所有分支與已刪除的檔案,找出 API key 與其他密鑰。逐一報告每個命中結果,附上檔案與 commit 參照位置,說明每一枚命中的金鑰是否仍然有效,並報告每一個 repository 是否已開啟 secret scanning 與推送保護(push protection)。
預防方式
為帳戶設一個天花板,並確認警報會落在你真的會看的地方
用書面向經營你雲端帳戶的公司問一個問題:當我的帳戶超過我設定的上限時,付費使用會停止,還是會繼續運作、繼續向我計費?把答覆留存下來。然後把你真的會讀的電子郵件地址和手機號碼放進帳戶,並保持付款卡片資料有效,因為一筆無聲失敗的付款,會拿掉大多數人唯一依賴的那個訊號。把免費額度當成起始餘額,永遠不要當成一道牆。
假設任何曾經接近共用程式專案的東西都已經公開,並照這個前提撤銷金鑰
撤銷並更換每一枚曾經放進程式專案裡的金鑰,包含你認為是私有的專案。刪掉檔案並不夠;網站會保留它背後的舊版本,而金鑰在有人撤銷它之前一直有效。為你擁有的每一個專案開啟程式碼託管平台的 secret scanning 與推送時封鎖(block-on-push)設定,並且把會花錢的金鑰,從你正在學習或做實驗的東西上全部拿掉。
外洩的金鑰只讓你付一次代價;沒有天花板的帳戶,每天都會讓你有損失。