今天上午,有個哥們在群裡發了一句話:
"axios 被投毒了。"
我第一反應是不可能。axios 每週 1 億次下載,npm 上 Top 10 的套件,誰敢動它?
然後我去翻了 GitHub issue,翻了安全公司的分析報告。越看越不對勁。
axios 的 GitHub 倉庫裡,一行惡意程式碼都沒有。你盯著原始碼看一萬遍,什麼都發現不了。
問題根本不在原始碼裡。
有人偷了 axios 維護者的 npm 帳號,繞過 GitHub,直接往 npm registry 發了兩個「官方版本」。
axios 程式碼本身沒改。只是在 package.json 的相依裡加了一個你從沒見過的套件:plain-crypto-js。
你 npm install 的瞬間,這個包的 postinstall 腳本自動跑起來:檢測作業系統,下載遠端控制木馬(RAT),連上攻擊者伺服器。然後自我刪除,把 package.json 替換成乾淨版本。
你事後翻 node_modules,什麼痕跡都沒有。
就好像你去五金行買了一把鎖,品牌對、包裝對、外觀對,但裡面被人換成了帶後門的。你裝上了,用著正常,別人隨時能開你家門。一般漏洞是鎖有缺陷,換一把就行。這次是鎖在到你手裡之前就被掉包了。
我把時間線拉出來:
T-18 小時:攻擊者用一次性帳號發佈了 [email protected]。
注意,這個版本是乾淨的。內容就是合法 crypto-js 的複製品,零惡意程式碼。
為什麼要發一個乾淨版本?在 npm 上建立發佈歷史。一個零歷史的新包突然被大包相依,會觸發安全警報。先「養號」,18 小時後再動手。
T-30 分鐘:發佈 [email protected],注入惡意 postinstall 腳本。
T=0:用被盜的維護者帳號,發佈 [email protected]。
T+39 分鐘:發佈 [email protected]。1.x 和 0.x 兩條版本線,一次全覆蓋。
T+3 小時:npm 下架惡意版本,窗口關閉。
18 小時預埋,39 分鐘把兩條版本線全覆蓋,3 小時後窗口關閉,痕跡自毀。
安全公司 StepSecurity 的評價是「針對 npm Top 10 套件有記錄以來最精密的供應鏈攻擊之一」。
還有個細節:惡意載荷在 npm install 開始後 2 秒內就開始向攻擊者伺服器回傳資訊。比 npm 解析完其他相依還快。你來不及按 Ctrl+C。
npm registry 和 GitHub 是兩個獨立系統。你在 GitHub 上看到的程式碼,和你 npm install 裝到的東西,可以完全不是同一個東西。
有維護者的 npm token,就能繞過 GitHub 的程式碼審查、CI/CD、所有你能看到的流程,直接往 registry 發包。
axios 所有合法的 1.x 版本都透過 GitHub Actions 的 OIDC Trusted Publisher 機制發佈,有密碼學簽名,和 GitHub 工作流程綁定。1.14.1 沒有。純手動發佈,沒有 OIDC 綁定,沒有 gitHead。
這個差異寫在 npm registry 的元資料裡。但你平時裝套件的時候查過 registry 元資料嗎?
我也沒查過。
用了 axios 的專案,花 5 分鐘跑一遍。
第一步:查 lockfile
打開你的 package-lock.json、pnpm-lock.yaml 或 yarn.lock,搜尋這三個關鍵字:
三個都沒有?大概率安全。後面幾步也值得做。
第二步:清快取
npm cache clean --force
踩坑預警:CI 環境也要清。GitHub Actions、GitLab CI 的 node_modules 快取和 npm 快取裡如果殘留了惡意 tarball,下次建置還會命中。別只清本地。
第三步:鎖死版本
在你的 package.json 或 lockfile 裡明確指定版本,例如:
"axios": "1.14.0"
注意是 "1.14.0",不是 "^1.14.0"。^ 意味著自動升級到最新相容版本,這次恰恰是這個機制讓惡意版本被裝上的。惡意版本雖然已經下架,但顯式鎖定是個好習慣。
第四步:審計 install 腳本
grep -r '"postinstall"' node_modules/*/package.json
這次的載體就是 postinstall。順手看看你其他相依有沒有可疑的 install 腳本。
激進做法:在 .npmrc 裡加上 ignore-scripts=true,全域禁止執行腳本。但 esbuild、sharp 這些套件也靠 postinstall 下載二進位檔案,全禁可能影響建置,自己權衡。
第五步:確認中招了?當作機器已經失控處理
不是「可能要換密碼」。是現在就輪換所有憑證:
CI 機器中招的話,檢查 CI secrets 是否外洩。
查異常進程與網路連線,關注 sfrclak.com:8000 這個位址。
RAT 跑起來之後,你機器上的一切對攻擊者都是透明的。別僥倖。
很多開發者的直覺是:axios 每週 1 億下載,總不會出事吧。反過來想,越熱門的套件,攻擊者的投入產出比越高。投毒一個每週 100 下載的套件沒人在乎,投毒一個每週 1 億下載的套件,3 小時窗口就夠覆蓋成千上萬個專案。
這次 axios 的原始碼沒有任何問題。
問題出在發佈鏈上。你預設信任的那條從程式碼到 registry 的鏈路,才是該被稽核的東西。lockfile 鎖版本、審計 install 腳本、監控相依變更、關注 registry 元資料的發佈者簽名。不是有空再搞的事。
你的專案查了嗎?留言報個平安。身邊有用 axios 的朋友還不知道這事的,轉給他看一眼。