近來,頻繁發生的npm供應鏈攻擊令開發者們精疲力竭:
流行npm包faker.js和colors.js的作者為***“開源白嫖”而自毀項目,導致數千個應用崩潰;
知名npm包node-ipc的作者以“反戰”為名,向項目注入惡意代碼;
攻擊者針對Azure開發者,創建了向200多個惡意npm包以竊取PII(個人身份信息);
代號為“RED-LILI”的***發動了大規模npm供應鏈攻擊,一口氣發布近800個惡意npm包。
這一系列接連不斷的npm供應鏈攻擊令許多人開始懷疑:Node.js包究竟還值得信任嗎?對于這個問題,知名開源框架sharedb/ottypes作者SephGentle通過一篇文章給出了他的回答:“Node.js包已不值得信任。”
npm的根本問題文章開頭,SephGentle就明確指出:“npm的根本問題是,你安裝的所有軟件包都可以在計算機上執行任何操作。”
而這個“任何”包括:閱讀電腦上的所有文件,例如電子郵件、密碼等所有內容;編輯、刪除或者給文件加密碼鎖;在互聯網上做任何它想做的事;運行子進程、更改操作系統設置、安裝關鍵日志記錄器……
舉個例子,本來你只是想簡單安裝一個leftpad模塊圖省事,結果它其實擁有對服務器和網頁的完整訪問權限,包括訪問我們的個人隱私數據。
當然了,可能大多數的Node.js包和模塊都沒有惡意,但不得不說,這種仿佛敞開大門歡迎所有人來參觀的設定有一定隱患。SephGentle對此感慨:“坦率地說,我很驚訝供應鏈攻擊居然沒有更頻繁地發生。”
不過,正如SephGentle所說,即便知道這個隱患,我們也很難先發制人地找出哪些Node.js包有問題,或者哪些開發人員不值得信任。
說到這里,可能會有人提到與Node.js一樣同為JavaScript運行時卻更為安全的Deno:Deno對于各種訪問權(文件、網絡和環境)都有嚴格限制。但SephGentle認為:“我認為它(Deno)還不夠好。”
Deno允許開發者在命令行中指定程序可執行哪些類型的操作、訪問哪些權限等,但其不足之處在于允許范圍過大了。例如,開發者正在***一個網絡服務器,難道就要允許leftpad可訪問全部互聯網?同理,即便開發者正在***文件服務器,leftpad也不應訪問其全部文件系統。
SephGentle對此總結道:“Deno或許是一個好的開始,但它分得還不夠細。”因此,SephGentle還是想針對Node.js當前的處理方式提出可改進的地方,而此時,他注意到了OpenBSDAPI的pledge程序。
功能令牌或許是突破口?OpenBSDAPI中pledge程序的工作方式是:當程序開始但還未做任何事情之前,開發者需做出一套設定以確保該程序將僅使用某些資源,例如:“我保證這個程序不會訪問/some/path之外的任何文件,也不會連接到除example.com之外的其他節點。”這樣的話,即便該程序被入侵,也無法實行權限之外的行為。
在此靈感啟發下,SephGentle認為Node.js的工作方式可以做出一些改變,以徹底解決現存隱患:
可添加一個名為capabilities的新內置Node.js庫,用來分發功能令牌,且該令牌只能由capabilities庫創建。
在進行任何特權操作時(如訪問文件系統、網絡、硬件、生成子進程、加載原生npm模塊等等),調用者需在相關函數中添加相符的功能令牌。
每個功能令牌都要設定一個范圍,指定該令牌的持有者可以做什么,且后續capabilities庫也只能在此基礎上縮小功能,不能擴大。
當程序啟動時,只有你的主模塊可以擁有“可以做任何事”的功能。之后,你可以縮小并將此功能令牌傳遞給其他包,具體縮小范圍取決于你希望它們做什么。
以上四步如能完美落實,相信npm供應鏈攻擊將大幅減少,現階段“Node.js包是否值得信任”的問題或許也就可以解決。
但SephGentle坦言,如果將目光聚焦到具體實施細節,會發現有很多棘手問題還需優化:
1、開發者應如何準確表達功能令牌的權限范圍?
2、要如何安全地將“通配符”令牌傳遞給主模塊?
3、是否存在一些JavaScript技巧可讓攻擊者輕松避開整個系統?又有什么***可以讓我們在嚴格功能模式下,鎖定更大范圍的JavaScript?
截止目前,SephGentle還找出這些問題的答案,因此他呼吁道:“這是一個值得接受的挑戰,畢竟它關乎計算機和用戶數據的安全。JavaScript生態系統中有很多聰明人,希望你們能站出來接受這個挑戰。”
“應假設所有開源軟件包都是惡意的”SephGentle的這篇文章在HN上引起了巨大討論,Deno、Socket(一個由npm維護者構建的新工具,用于幫助解決JavaScript供應鏈安全問題)等項目核心開發者也紛紛留言。
Deno核心團隊成員:
“我們過去也曾考慮過Deno基于功能限制的安全性,但我們的結論是——在不默認凍結所有原型和對象的情況下,這是不可能在JavaScript中安全實現的,因為你需要確保功能令牌永遠不會泄漏。
由于JavaScript的動態特性,攻擊者可以竊取令牌。而僅僅凍結所有內在原型和對象也是不夠的,因為他們總會找到轉移代幣的***。”
Socket創始人:
“我完全同意我們應該假設所有開源軟件包都可能是惡意的想法。Socket.dev使用“深度包檢查”來描述開源包的行為。通過實際分析包代碼,Socket可以檢測包何時使用與安全相關的平臺功能,如網絡、文件系統或shell。
通過這種方式,Socket可以檢測供應鏈攻擊的跡象,包括引入安裝腳本、混淆代碼、高熵字符串或使用特權API。總之,我們正在采用一種全新的***來解決行業的安全領域中最困難的問題之一,且這個行業一直癡迷于報告已知的漏洞。”
許多網友對此也看法不一:
@chha:“至少在目前的情況下,的確沒有任何軟件包或存儲庫值得信任。文章所提出的***只能解決問題的一半,我們還需要一種能使包接受審查的***,其中發布者和存儲庫的包簽名必須是強制性的。”
@didip:“在Node.js誕生之初,npm公司有一個營銷術語:包越小,可重用性越好。可現在,它似乎永遠玷污了Node.js生態系統,這也就是為什么我對Deno更為期待。”
那么,對于SephGentle提出的解決方案,你有什么看法嗎?
參考鏈接:
https://josephg.com/blog/node-sandbox/
https://news.ycombinator.com/item?id=30988034
END
《新程序員001-004》全面上市,對話世界級大師,報道中國IT行業創新創造
成就一億技術人