被自己的備用鑰匙鎖住 72 小時:一場 npm 虛驚
什麼是 npm?我為什麼用它,又是怎麼被自己的安全機制反鎖
npm,全名 Node Package Manager,是整個 JavaScript/Node.js 世界共用的「零件倉庫」。
想像一下:全世界寫程式的人,每天都要重新造輪子——要處理日期格式、要發 Email、要讀寫檔案,這些小零件幾乎每個專案都用得到。npm 就是那個大家把自己做好的零件,放到公共倉庫讓所有人直接拿去用的地方。你不用自己刻一顆螺絲,打一行 npm install 就能把別人做好的零件裝進自己的專案。
我自己就是這樣用它的。
我做了一支小工具叫 mcpost,讓我可以直接從任何一台電腦、任何一個終端機,把文章一行指令發到 MakeClass,不需要把 MakeClass 整包 2GB 的私有原始碼 clone 下來。原本這個功能是埋在主程式裡的,後來我把它單獨抽出來,放到 npm 這個公共倉庫,變成一個獨立的小套件——就像 Notion 自己也把「怎麼呼叫 Notion API」做成一個叫 @notionhq/client 的套件放上 npm,你不需要 clone Notion 的原始碼,一樣可以呼叫 Notion。npm 讓「發文能力」跟「公司內部原始碼」徹底脫鉤。
前幾天我想幫 mcpost 加一個新功能——讓它可以列出我自己有哪些頻道,發文時直接選,不用再去網頁上背頻道網址。功能寫完了,要發布新版本上 npm 的時候,卡住了。
npm 要求我做一次兩步驟驗證。我很自然地打開手機裡的 Google Authenticator,抓了一組驗證碼貼上去——結果一直被拒絕。試了三四次都不對,才發現:我的 npm 帳號早就換成了用 Face ID/安全金鑰驗證,根本沒有註冊過驗證器 App 這條路,難怪怎麼試都是錯的。
情急之下,AI 建議我改用「備用碼」(recovery code)試試看——那是當初設定兩步驟驗證時,系統要你存起來以防手機弄丟時能用的一組緊急密碼。用了之後,帳號確實通過驗證了……
下一秒,npm 系統就自動把我的帳號停權了 72 小時。
原因寫得很清楚:只要偵測到有人用「備用碼」登入,不管是不是本人,npm 一律先假設「這可能是帳號被盜」,自動鎖起來讓你沒辦法發布任何東西、改任何設定,防止真正的攻擊者拿著偷來的備用碼搞破壞。我這才意識到,備用碼從來就不是「另一種正常的驗證方式」,而是「拆了就會觸發警報的緊急逃生門」。
一開始有點慌——3 天不能發布,會不會什麼都動不了?
冷靜下來查了一輪才發現,是虛驚一場。npm 帳號被鎖,鎖住的只有「用這個帳號把新版本推上 npm 公開倉庫」這一件事,不影響其他任何東西:本機開發、npm install 裝套件、跑 build、Firebase 部署、Git push 觸發自動上線……全部照常運作,因為那些動作跟「有沒有權限對 npm 的公開帳號寫入」完全無關。甚至連 mcpost 這支工具本身,因為刻意寫成不依賴任何外部套件的單一檔案,我直接把新版程式碼複製到本機已經裝好的位置,不用等 npm 解封就能先用。
真正被卡住的,只有「讓全世界的人透過 npm 安裝到最新版」這件事,等 3 天後帳號恢復就補做一次。
這次的教訓很簡單:緊急備用方案往往比正常路徑更敏感,用之前最好先搞清楚它會觸發什麼後果,不要臨陣才發現自己開的是警報器,不是側門。