盤與倉庫密鑰審計(jì)指南)
先說事件結(jié)論Mozilla 在發(fā)現(xiàn)一個(gè) Firefox 擴(kuò)展簽名密鑰的未加密副本出現(xiàn)在 GitHub 倉庫后直接執(zhí)行了吊銷處理。簽名密鑰一旦落入公開倉庫就不能再假設(shè)它安全這跟有沒有被人下載過無關(guān)而是默認(rèn)已經(jīng)泄露。本文不打算復(fù)述一遍新聞標(biāo)題而是從簽名機(jī)制、事件技術(shù)路徑、普通用戶處置、擴(kuò)展開發(fā)者應(yīng)對、倉庫密鑰審計(jì)五個(gè)層面展開最后給出一套可以直接復(fù)用的排查流程。如果你正在使用 Firefox、給 Firefox 寫過擴(kuò)展、或者 GitHub 上任何一個(gè)倉庫存放過證書、密鑰、口令這類文件這篇文章值得看完。前面講機(jī)制和影響后面給命令和工具可以直接照著操作。1. 事件核心速覽項(xiàng)目說明事件類型密鑰泄露與吊銷處置涉及方Mozilla、Firefox 用戶、擴(kuò)展開發(fā)者、GitHub 倉庫維護(hù)者核心問題Firefox 擴(kuò)展簽名密鑰的未加密副本出現(xiàn)在公開 GitHub 倉庫Mozilla 的動(dòng)作吊銷該簽名密鑰降低被惡意利用的風(fēng)險(xiǎn)風(fēng)險(xiǎn)等級高。簽名密鑰可用于偽造擴(kuò)展簽名進(jìn)而影響擴(kuò)展安裝與更新鏈路普通用戶影響需確認(rèn) Firefox 已更新、擴(kuò)展安裝與更新正常擴(kuò)展開發(fā)者影響可能遇到簽名失效、擴(kuò)展被禁用或需要重新提交簽名開發(fā)者通用教訓(xùn)任何密鑰都不應(yīng)進(jìn)入代碼倉庫尤其是未加密副本從公開報(bào)道看這次事件的核心處置動(dòng)作是吊銷而不是刪除文件后繼續(xù)使用。這個(gè)選擇本身就是安全行業(yè)的標(biāo)準(zhǔn)做法密鑰一旦公開無論是否真的被濫用都必須立刻視為不可信然后啟動(dòng)輪換流程。2. 什么是 Firefox 簽名密鑰為什么被吊銷值得關(guān)注2.1 簽名密鑰在 Firefox 生態(tài)里的作用Firefox 從較早期版本開始就要求擴(kuò)展必須經(jīng)過簽名才能被安裝到正式版本中。這個(gè)簽名的目的有兩個(gè)確認(rèn)擴(kuò)展確實(shí)來自某個(gè)開發(fā)者或發(fā)布渠道而不是第三方偽造。確認(rèn)擴(kuò)展打包文件xpi在發(fā)布后沒有被篡改過。瀏覽器在安裝擴(kuò)展、檢查擴(kuò)展更新時(shí)會驗(yàn)證簽名。如果簽名無效Firefox 會拒絕安裝或禁用該擴(kuò)展。這套機(jī)制和 Windows 驅(qū)動(dòng)簽名、macOS 應(yīng)用公證是同一個(gè)思路——用一條信任鏈保證用戶拿到的代碼是可信的。Mozilla 官方擴(kuò)展商店 AMOaddons.mozilla.org負(fù)責(zé)對擴(kuò)展進(jìn)行簽名。開發(fā)者提交擴(kuò)展到 AMO 后AMO 會使用 Mozilla 的簽名密鑰對擴(kuò)展包進(jìn)行簽名然后把簽名后的包提供給用戶下載。2.2 密鑰泄露的風(fēng)險(xiǎn)模型如果攻擊者拿到了 Firefox 擴(kuò)展簽名過程中使用的私鑰他可以做這些事偽造一個(gè)簽名有效的惡意擴(kuò)展。對已經(jīng)發(fā)布的合法擴(kuò)展進(jìn)行重打包植入惡意代碼后重新簽名。在某些場景下干擾擴(kuò)展更新通道讓用戶接收到被篡改的版本。所以密鑰泄露不是改個(gè)密碼就行的問題而是整條信任鏈?zhǔn)艿搅送{。Mozilla 選擇吊銷密鑰本質(zhì)上就是切斷這條可能被污染的信任鏈強(qiáng)制所有依賴它的環(huán)節(jié)重新建立信任。2.3 密鑰吊銷意味著什么吊銷不是刪除一個(gè)文件那么簡單。吊銷意味著使用該密鑰簽發(fā)的所有擴(kuò)展或組件需要重新用新密鑰簽名。Firefox 需要針對密鑰輪換發(fā)布相應(yīng)更新。擴(kuò)展開發(fā)者可能需要重新提交或重新下載簽名包。用戶在密鑰輪換完成前可能遇到擴(kuò)展校驗(yàn)異常的情況。這里有一個(gè)容易混淆的點(diǎn)吊銷針對的是密鑰本身而不是特定版本的 Firefox。對你正在使用的擴(kuò)展的影響取決于該擴(kuò)展是否仍然依賴舊密鑰以及 Firefox 更新后是否已經(jīng)切換到新的校驗(yàn)邏輯。3. 事件技術(shù)分析未加密副本進(jìn)入 GitHub 的典型風(fēng)險(xiǎn)3.1 密鑰是怎么進(jìn)入公開倉庫的從公開信息看這次事件的直接原因是未加密副本進(jìn)入 GitHub。這種泄露在開發(fā)者群體里非常常見一般有幾種路徑曾經(jīng)是私有倉庫后來被改成公開而敏感文件一直留在歷史提交里。備份腳本或打包腳本把整個(gè)配置目錄推送到倉庫密鑰文件被當(dāng)成普通文件一起上傳。為了在另一臺機(jī)器上復(fù)現(xiàn)問題開發(fā)者把本機(jī)配置壓縮后臨時(shí)上傳到倉庫忘記刪除。CI 構(gòu)建過程把密鑰明文輸出到日志或產(chǎn)物目錄隨后被提交。無論是哪一種只要文件進(jìn)入過一個(gè)公開倉庫就不能再假設(shè)只有自己看過。Git 的歷史記錄、Fork、鏡像、第三方抓取服務(wù)都可能保留副本。這也是為什么安全社區(qū)反復(fù)強(qiáng)調(diào)倉庫里出現(xiàn)密鑰處理方式不是刪文件而是吊銷并輪換。3.2 未加密為什么是關(guān)鍵未加密副本這個(gè)詞很關(guān)鍵。如果密鑰文件本身使用強(qiáng)密碼加密攻擊者拿到的是一份密文在沒有口令的情況下無法直接使用。但未加密意味著拿到文件的人可以直接讀取私鑰內(nèi)容、直接用于簽名操作。所以不要抱著這個(gè)倉庫訪問量很小我很快就刪掉了的僥幸心理。密鑰一旦以明文形式出現(xiàn)在公網(wǎng)時(shí)間窗口內(nèi)有多少人抓取過是根本沒法統(tǒng)計(jì)的。吊銷是唯一穩(wěn)妥的處置路徑。3.3 從發(fā)現(xiàn)到吊銷的標(biāo)準(zhǔn)處置鏈路不管是 Mozilla 這次事件還是任何公司的密鑰泄露事件標(biāo)準(zhǔn)處置鏈路基本是一致的確認(rèn)密鑰確實(shí)泄露并且泄露范圍是公開的。評估泄露密鑰的使用范圍與權(quán)限邊界。立即吊銷密鑰停止其繼續(xù)使用的資格。生成新密鑰替換所有依賴舊密鑰的系統(tǒng)與服務(wù)。通知可能受影響的用戶或開發(fā)者。復(fù)盤泄露路徑補(bǔ)上流程和工具層面的漏洞。這次事件里Mozilla 沒有選擇先把倉庫刪掉再看情況而是直接吊銷說明內(nèi)部對密鑰泄露的響應(yīng)已經(jīng)進(jìn)入標(biāo)準(zhǔn)流程。這種處置方式本身也值得所有開發(fā)者學(xué)習(xí)。4. 普通 Firefox 用戶應(yīng)該做什么普通 Firefox 用戶不需要做什么復(fù)雜操作但建議按下面的步驟快速自查一遍。4.1 確認(rèn) Firefox 版本與更新狀態(tài)在 Firefox 地址欄輸入about:about找到關(guān)于 Firefox入口或者直接在菜單里打開幫助 - 關(guān)于 Firefox。Firefox 會自動(dòng)檢查更新。如果發(fā)現(xiàn)有可用更新建議立即安裝并重啟瀏覽器。更新是拿到密鑰輪換修復(fù)的最直接方式。Mozilla 在發(fā)現(xiàn)密鑰問題后通常會通過常規(guī)版本更新把相關(guān)的修復(fù)和安全配置下發(fā)到用戶端。4.2 檢查已安裝擴(kuò)展是否正常在地址欄輸入about:addons檢查每個(gè)擴(kuò)展的狀態(tài)。如果你發(fā)現(xiàn)有擴(kuò)展被自動(dòng)禁用、提示無法驗(yàn)證簽名或已損壞不要急著下載所謂的破解版或未簽名版來繞過限制那是更危險(xiǎn)的做法。正確的處理方式是確認(rèn)該擴(kuò)展是否仍在其官方頁面提供更新版本。重新從 AMO 等官方渠道安裝。如果重新安裝后仍然提示簽名錯(cuò)誤等待擴(kuò)展開發(fā)者重新簽名并發(fā)布更新。4.3 如果 Firefox 無法自動(dòng)更新的處理方式部分企業(yè)環(huán)境會通過組策略或管理配置鎖定 Firefox 版本終端用戶無法自行更新。這種情況下建議聯(lián)系管理員確認(rèn)組織內(nèi)的 Firefox 是否已經(jīng)應(yīng)用最新的安全更新。個(gè)人用戶如果更新失敗優(yōu)先檢查磁盤空間、網(wǎng)絡(luò)連接和殺毒軟件攔截而不是從非官方渠道下載安裝包。5. 對擴(kuò)展開發(fā)者的影響與處理建議5.1 簽名失效的表現(xiàn)如果你是 Firefox 擴(kuò)展開發(fā)者這次密鑰吊銷可能對你的工作流產(chǎn)生影響。具體表現(xiàn)通常是本地開發(fā)時(shí)通過 web-ext 工具加載的臨時(shí)擴(kuò)展在自簽名或使用開發(fā)簽名后仍然提示無效。通過 AMO 提交的擴(kuò)展在審核后返回簽名失敗。用戶反饋擴(kuò)展在更新后突然被禁用。遇到這些情況先去 AMO 開發(fā)者中心查看當(dāng)前擴(kuò)展的簽名狀態(tài)。如果 Mozilla 已經(jīng)啟用了新的簽名密鑰舊密鑰簽發(fā)的包就會失效你需要重新提交或重新下載簽名文件。5.2 重新簽名與版本發(fā)布建議重新簽名后建議檢查以下內(nèi)容擴(kuò)展的 manifest.json 中的版本號是否需要提升。本地存儲的已簽名 xpi 是否為最新生成。如果是自托管分發(fā)需要確認(rèn)用戶的更新源指向的是新簽名文件。對于依賴 CI 自動(dòng)打包發(fā)布的團(tuán)隊(duì)還需要檢查構(gòu)建流程里的簽名步驟是否寫死了舊密鑰。密鑰輪換后CI 環(huán)境中的密鑰文件要同步替換否則下一次構(gòu)建會直接失敗或在靜默狀態(tài)下生成無效簽名。5.3 測試通道與正式通道分開管理給擴(kuò)展打開發(fā)簽名和正式發(fā)布簽名最好使用不同的密鑰體系。這樣即使開發(fā)密鑰泄露也不會直接威脅到正式發(fā)布版本。Mozilla 的 AMO 體系本身也區(qū)分不同簽名場景建議開發(fā)者仔細(xì)閱讀其文檔不要把測試通道的簽名文件復(fù)用到正式發(fā)布。6. 從事件看密鑰管理與 GitHub 倉庫安全最佳實(shí)踐這次事件給所有 GitHub 用戶提了個(gè)醒倉庫里的敏感文件管理比大多數(shù)開發(fā)者想象中更嚴(yán)格。下面的實(shí)踐建議適用于任何團(tuán)隊(duì)建議直接收藏。6.1 密鑰應(yīng)該放在哪里密鑰不應(yīng)該放在項(xiàng)目代碼目錄里更不應(yīng)該進(jìn)入 Git 倉庫。正確的存放位置包括專用密鑰管理服務(wù)KMS、Vault、云廠商 Secrets Manager。本地密碼管理器。硬件安全模塊或安全 U 盤。環(huán)境變量或受保護(hù)的配置文件且不進(jìn)入版本控制。如果你的項(xiàng)目確實(shí)需要把密鑰寫入配置文件一定要確保配置文件被 .gitignore 排除并且只允許在部署階段由 CI 或運(yùn)維平臺注入。6.2 加密存儲與訪問控制如果密鑰必須以文件形式存在至少要做到文件本身加密存儲。訪問權(quán)限按最小權(quán)限原則分配。目錄和文件的系統(tǒng)權(quán)限嚴(yán)格限制。定期審計(jì)誰訪問過這些文件。不要把倉庫是私有的當(dāng)作安全措施。私有倉庫也可能被誤改公開也可能因?yàn)橘~號泄露、協(xié)作庫被外部訪問而暴露。真正安全的做法是密鑰根本不進(jìn)入倉庫。6.3 git 歷史中的密鑰泄漏問題很多密鑰泄露不是發(fā)生在最新代碼里而是隱藏在舊的 git 提交歷史中。即使你刪除了當(dāng)前文件歷史記錄里的副本依然存在。這意味著清理工作不是刪一次文件那么簡單。如果是 GitHub 倉庫需要聯(lián)系 GitHub 支持處理歷史記錄如果是自建 Git 服務(wù)需要對歷史進(jìn)行重寫并強(qiáng)制推送。但更穩(wěn)妥的做法仍然是吊銷并輪換密鑰而不是只清理歷史。6.4 倉庫可見性審計(jì)建議定期檢查組織下的所有倉庫確認(rèn)每個(gè)倉庫是否真的需要公開??梢杂?GitHub CLI 快速列出倉庫的可見性# 列出當(dāng)前賬號下所有倉庫及其可見性 gh repo list --json name,visibility # 查看某個(gè)倉庫詳情 gh repo view owner/repo --json name,visibility,url針對已經(jīng)公開的倉庫重點(diǎn)檢查這幾個(gè)位置README 或文檔中的示例配置是否包含真實(shí)密鑰占位。測試用例里是否有硬編碼密鑰。歷史提交中是否存在配置文件。CI 日志和發(fā)布產(chǎn)物是否包含敏感信息。6.5 密鑰輪換機(jī)制不要等密鑰泄露了才想到輪換。合理的做法是所有密鑰都設(shè)置定期輪換周期并且有自動(dòng)化的輪換流程。密鑰過期時(shí)間、輪換責(zé)任人、輪換后的驗(yàn)證步驟都應(yīng)該寫清楚。這樣一旦發(fā)生泄露你只需要提前執(zhí)行已有的輪換流程而不是臨時(shí)想辦法。7. 如何用工具審計(jì)倉庫中是否存在泄漏密鑰與其擔(dān)心密鑰是否已經(jīng)泄露不如直接在本地把倉庫掃一遍。下面介紹三個(gè)常用工具覆蓋提交前攔截、歷史掃描、實(shí)時(shí)掃描三個(gè)環(huán)節(jié)。7.1 gitleaks全量掃描倉庫歷史gitleaks 可以掃描整個(gè) git 歷史找出所有提交中出現(xiàn)的密鑰模式。安裝后在倉庫目錄執(zhí)行g(shù)itleaks detect --source . --report-path gitleaks-report.json --report-format json掃描結(jié)果會輸出到 gitleaks-report.json里面包含命中的文件路徑、提交哈希和密鑰類型。也可以在 CI 里直接跑gitleaks detect --source . --verbose --redact--redact參數(shù)會在輸出中遮住密鑰內(nèi)容避免掃描結(jié)果本身又成為泄露源。7.2 git-secrets提交前攔截git-secrets 是一個(gè)提交前鉤子工具可以在 git commit 之前檢查暫存內(nèi)容里是否包含密鑰。安裝方式git secrets --install git secrets --register-aws--register-aws會注冊 AWS 密鑰格式的檢測規(guī)則。如果要檢測自定義后綴比如 PEM 私鑰可以手動(dòng)追加規(guī)則git secrets --add -----BEGIN (RSA|EC|OPENSSH|PRIVATE) KEY-----安裝后每次提交都會自動(dòng)檢查。執(zhí)行手動(dòng)掃描可以用git secrets --scan7.3 用 git 自帶命令搜索私鑰特征如果沒有安裝任何工具也可以用 git 命令直接在歷史里搜索私鑰特征# 在全部歷史中搜索私鑰頭部 git rev-list --all | xargs git grep -l BEGIN PRIVATE KEY 2/dev/null# 在全部歷史中搜索常見密鑰文件名 git rev-list --all | xargs git grep -l id_rsa\|\.pem\|\.pfx\|keystore 2/dev/null注意這種搜索只能作為輔助手段因?yàn)槊荑€可能有多種編碼形式。而且搜索結(jié)果命中的文件不代表一定泄露還需要人工確認(rèn)。7.4 GitHub 自帶 Secret ScanningGitHub 原生提供 Secret Scanning 和 Push Protection 功能。Secret Scanning 會掃描倉庫歷史中的已知廠商密鑰格式一旦發(fā)現(xiàn)會向倉庫管理員發(fā)送告警。Push Protection 會在開發(fā)者試圖把密鑰推送到公開倉庫時(shí)直接攔截推送。建議所有團(tuán)隊(duì)都開啟這兩個(gè)功能并把 Mozilla 這次事件作為案例寫進(jìn)團(tuán)隊(duì)的安全培訓(xùn)文檔里。8. 常見問題排查與后續(xù)觀察問題現(xiàn)象可能原因排查方式處理建議Firefox 提示擴(kuò)展無法驗(yàn)證簽名擴(kuò)展簽名密鑰已輪換舊簽名失效查看 about:addons 中的錯(cuò)誤提示從 AMO 重新安裝最新版或等待開發(fā)者更新Firefox 無法檢查更新網(wǎng)絡(luò)受限或更新服務(wù)被攔截查看關(guān)于 Firefox頁面中的更新狀態(tài)檢查網(wǎng)絡(luò)與代理設(shè)置必要時(shí)手動(dòng)下載安裝包擴(kuò)展被停用但重新安裝仍然報(bào)錯(cuò)本地緩存了舊的簽名包清除瀏覽數(shù)據(jù)或刪除擴(kuò)展后重裝確認(rèn)擴(kuò)展官方頁面已發(fā)布重新簽名的版本git 倉庫歷史中存在密鑰文件早期誤提交使用 gitleaks 確認(rèn)泄露范圍優(yōu)先吊銷并輪換密鑰不要只依賴刪除歷史第三方工具掃描出大量密鑰告警測試配置文件或示例代碼誤報(bào)逐條確認(rèn)是否真實(shí)密鑰對真實(shí)密鑰立即輪換偽密鑰可加入白名單Secret Scanning 告警未被處理倉庫管理員未配置通知檢查 GitHub Security 頁面建立告警處理 SLA明確責(zé)任人如果事件后續(xù)有新的官方公告建議關(guān)注 Mozilla 安全博客和 AMO 開發(fā)者中心的公告而不是依賴社交媒體上的二手信息。對于一些不活躍維護(hù)的舊擴(kuò)展如果開發(fā)者沒有在合理時(shí)間內(nèi)完成重新簽名可以考慮尋找替代擴(kuò)展避免一直使用簽名失效的版本。9. 總結(jié)與建議這次 Mozilla 吊銷 Firefox 簽名密鑰的事件真正值得關(guān)注的不是某一個(gè)擴(kuò)展能不能用而是密鑰管理這條線被完整地暴露了一次。普通用戶最應(yīng)該驗(yàn)證的是Firefox 是否已經(jīng)更新、擴(kuò)展是否都能正常安裝和更新。擴(kuò)展開發(fā)者最應(yīng)該驗(yàn)證的是自己的 CI 流程、簽名配置是否依賴了可能已經(jīng)被輪換的舊密鑰。GitHub 倉庫維護(hù)者最應(yīng)該驗(yàn)證的是自己的倉庫歷史里有沒有私鑰、證書、口令這類文件不要等到 Secret Scanning 告警或者更糟的泄露事件發(fā)生后再被迫做一次緊急處置。這次事件最容易踩的坑是以為刪掉文件就沒事了。密鑰一旦進(jìn)入公開倉庫唯一正確的路徑是立即吊銷、馬上輪換。把這條原則沉淀到團(tuán)隊(duì)流程里比任何一次單獨(dú)的清理都更有價(jià)值。接下來值得做的事很簡單打開終端在你有權(quán)限的倉庫上跑一遍 gitleaks看看掃描結(jié)果。如果沒有任何命中說明你的倉庫衛(wèi)生狀況不錯(cuò)如果有命中正好借這次事件把輪換流程走一遍。