《公開 Repo 密鑰外洩清除實錄》之一:.gitignore 的盲區與活密鑰偵測
這是一部關於開發者 Icekimo 與 AI 助理 Claude Fable 在 Debian 開發機 katharine 上,發現自己在 GitHub 公開 repo 洩漏敏感密鑰後,展開的一場驚心動魄的密鑰獵殺與歷史重寫實錄。
糟糕!我在 Synology NAS 上部署服務時,執行 `git status` 竟然看到了 `M .env`,但這檔案明明已經寫在 `.gitignore` 裡了。這是怎麼回事?
這是一個非常經典且危險的 Git 陷阱。`.gitignore` 的機制是「只擋未追蹤的檔案」。如果一個檔案在被加入忽略名單前就已經被 commit 追蹤,那日後就算補上忽略名單,Git 依然會持續監控並追蹤它的修改。這意味著你的敏感資訊極有可能已經進了 GitHub!
敏感檔案追蹤檢測
聽完 Claude Fable 的分析,Icekimo 驚覺不妙,立刻在開發機終端機輸入指令,掃描整個專案到底有多少敏感檔案被偷偷追蹤了:
$ git ls-files | grep -iE 'credential|secret|\.env|password|token|key'
.env
crowdsec_config/local_api_credentials.yaml
「居然連 CrowdSec 的 LAPI 憑證也進去了...」Icekimo 倒吸一口氣。此時,Claude Fable 提議立刻再掃描一次目錄,以防還有漏網之魚。
$ ls crowdsec_config/
local_api_credentials.yaml
online_api_credentials.yaml
果不其然,第三個沒人記得的敏感檔案 online_api_credentials.yaml 靜靜地躺在目錄裡。
確認 Repo 是否對外公開
為了確認災情,Icekimo 必須驗證這個 GitHub Repo 是否已被公開。他使用了一個不需要帶 Token 的 GitHub API curl 指令:
$ curl -s -o /dev/null -w "%{http_code}" https://api.github.com/repos/August-Icekimo/secure-gateway
200
「回傳 200... 專案真的是公開的。」Icekimo 感覺背後一陣涼風吹過,感凌涼啊。
評估洩漏嚴重性:值是「活的」還是「死的」?
既然已經公開了,那這些被推上去的密鑰現在是活的嗎?要怎麼比對而不把值印在終端機上(以防二次洩漏)?
我們可以利用 `git show` 從 commit 歷史中抓出舊值,並透過 SSH 抓取 NAS 上生產環境的現用值直接進行字串比對,只輸出比對結果,不印出密鑰本身。
Icekimo 照著寫了一段比對指令:
# 比對 CrowdSec bouncer key
$ repo_key=$(git show HEAD:.env | grep CROWDSEC_BOUNCER_KEY | cut -d= -f2)
$ live_key=$(ssh nas 'grep CROWDSEC_BOUNCER_KEY /volume1/docker/secure-gateway/.env' | cut -d= -f2)
$ [ "$repo_key" = "$live_key" ] && echo "MATCH: 洩漏是活的" || echo "不同:是輪替過的舊值"
依此類推,他們將三個檔案進行了全面檢測,整理出以下令人堪憂的狀態表:
| 檔案 | 洩漏內容 | 狀態 |
|---|---|---|
.env |
舊 bouncer key(其餘為 placeholder) | 死的(已輪替過) |
local_api_credentials.yaml |
舊 LAPI 密碼 | 死的 |
online_api_credentials.yaml |
CrowdSec CAPI 帳密 | 活的 ⚠️ 與 NAS 現值完全相同 |
「最關鍵的 CrowdSec 中央 API 帳密居然是現役的的!」Icekimo 握著滑鼠的手不禁微微顫抖,難道是這隻mouse有通靈體質?
第一階段的偵測宣告結束,公開倉庫中躺著隨時可被利用的現役帳密,這場安全漏洞的即刻救援,必須在服務零中斷的前提下立刻展開。