美國國家安全局NSA建議開發者應多使用保障記憶體安全的程式語言,如C#、Rust、Go、Java、Ruby、Swift

從程式語言層級確保記憶體安全,不只美國NSA建議,今年Prossimo專案也在推動

在本月10日,美國國家安全局(NSA)公開發表一份軟體開發指南,是針對軟體記憶體安全(Memory Safety)而來,建議開發者應多使用保障記憶體安全的程式語言,如C#、Rust、Go、Java、Ruby、Swift,以這些來取代C與C++,引起軟體開發界的討論。

事實上,關於C、C++的資安爭論已持續多年,但隨著記憶體安全問題受到越來越大的重視,開發者輕忽指標、記憶體配置的狀況太過普遍,而願意花心力檢測、有足夠經驗處理這類問題的程式設計者太少,而使得軟體資安漏洞層出不窮。

儘管為了降低這方面犯錯的機會,開發界持續宣導C/C++程式設計要重視記憶體管理,有些開發者的確能夠寫出足夠安全的C/C++程式碼,但對大多數程式設計師來說,卻可能並非易事,有些科技業者祭出記憶體安全機制來因應,但多年下來,犯錯比例仍是居高不下,這也使得另一條因應路線被持續探討,也就是多用具記憶體安全特性的程式語言,如此一來,即便是資安意識不足的開發人員,也因為開發環境的局限,而不用擔心記憶體管理的問題,減少犯錯的機會。而且,如今這類軟體開發安全措施的推動態勢,也從一些科技大廠而開始擴及國家政府機構。

多數軟體漏洞可歸咎於記憶體安全性不足

在今年5月,我們看到開源社群、科技大廠與美政府二度商討開源軟體安全對策,會後Linux基金會與開源安全基金會(OpenSSF)發布的開源軟體安全動員計畫白皮書中,替換不具記憶體安全(non-memory-safe)的程式語言,就是十大對策之一,並預計前兩年針對這方面投入經費550萬美元。

到了11月,美國NSA也對此公開表態。針對軟體記憶體安全問題,他們建議各組織在可能情況下,對於程式語言的採用,應考慮做出戰略性的轉變,從不具記憶體保護的C/C++,轉而使用具記憶體安全的其他程式語言,例如C#、Go、Java、Ruby與Swift等。

在這份公開文件中,NSA首先強調軟體記憶體安全的重要性,指出雖然開發人員經常進行嚴格測試,為軟體中的邏輯準備好應對意外情況,然而,各種可濫用的軟體漏洞,仍經常是基於記憶體問題而成。例如:記憶體緩衝區溢位,以及管理記憶體失當而導致的洩漏問題。

最近幾年已有更多這方面的研究,例如,微軟在2019年曾公開提出自我檢討,他們表示,在2006年到2018年間的安全漏洞,有70%源自記憶體的安全問題,Google在2020年也針對自家發展的瀏覽器Chrome提出檢討,當中也存在同樣高比例的記憶體安全漏洞。由於存在規模如此龐大的軟體開發缺失,駭客可利用這些漏洞來執行遠端程式攻擊,作為大舉入侵組織網路的第一步。

而在程式語言中,現今應用範圍最大且最常見的C與C++,方便之餘,多年來大家也經常詬病其安全性管制太少,而使得記憶體類型的漏洞總是無法徹底根絕。事實上,這兩種語言在記憶體管理上,提供了很大的自由度與彈性,相對地,用這些語言所開發的應用程式,其安全性將高度依賴開發者的處理方式,例如,是否對記憶體參照執行必要的檢查與驗證。因此,可能只要出現一個簡單的錯誤、疏忽,就會導致記憶體遭濫用的安全漏洞。

固然我們可以透過軟體分析工具偵測出許多記憶體管理問題,透過作業系統環境本身內建的機制,也能帶來某些程度的保護,但NSA認為,若能藉由已內建記憶體保護的程式語言來撰寫程式,即可避免或減少絕大多數的記憶體管理問題。

緩衝區溢位、管理不當,均是常見記憶體安全問題

記憶體安全,也就是有關於程式如何管理記憶體的一大類問題。這當中有哪些常見問題?

NSA指出,記憶體「緩衝區溢位」(buffer overflow)就是一例,也就是資料的存取意外超出緩衝區邊界(outside the bounds),另一個常見的安全問題則與記憶體分配有關。

簡單來說,系統程式在執行時可以分配新的記憶體位置,然後在不需要記憶體時,將其取消分配,此舉稱為釋放記憶體,但如果開發者不小心這麼做,新的記憶體可能會在程式執行過程中被重複分配,因此,記憶體並非總是在不再需要時被釋放,進而出現記憶體洩漏(memory leak)的問題,最終甚至導致可用的記憶體資源被使用殆盡。

此外,也有因邏輯錯誤而出現記憶體存取不安全的狀況。因為這樣的問題,程式可能試圖使用已經被釋放的記憶體,甚至重複釋放原本已被釋放的記憶體。例如,當程式語言允許使用尚未初始化的變數時,就會出現另一個問題,導致該變數使用之前在記憶體中該位置設置的值。

另一個值得注意的問題,則是條件競爭(Race condition)。例如,當程式存取相同資料,此時若出現兩個操作順序,可能會因此影響程式的結果,而發生這個問題。NSA強調,所有這些記憶體問題都是相當常見的現象。

而且,記憶體管理問題衍生安全漏洞只是其中一種類型的狀況,就算是不會遭到濫用的記憶體,也可能因為一些疏失而造成錯誤的程式結果,例如,降低執行效能或軟體本身無法執行。

針對上述種種軟體記憶體安全的問題,NSA指出,採用能夠自動管理記憶體的程式語言,像是C#、Rust、Go、Java、Ruby、Swift等,可協助避免開發者陷入某些類型的記憶體問題,以預防無意採用錯誤的記憶體管理方式。

但NSA也提醒,就算是使用這些內建記憶體保護的程式語言,也並非毫無風險,因為軟體有時仍需要執行不安全的記憶體管理功能,才能完成任務,而且,各種程式語言對記憶體的安全保護程度不一,因此不能單靠更換程式語言而確保軟體安全。

另一方面,對於無法立即轉向採用內建記憶體安全的程式語言的開發者,NSA建議,應透過安全測試來強化應用程式的安全性,包括進行靜態(SAST)與動態(DAST)的安全測試,而且最好是執行多個SAST及DAST工具,以提高找出記憶體問題的機率,確保應用程式的安全。儘管這可能會增加大量的工作負擔,卻可以帶來更安全的程式碼。

總之,NSA鼓勵組織儘可能採取多管齊下的方式,來強化記憶體管理的安全性。除了採用記憶體安全程式語言,還可同時輔以編譯器選項、工具分析及作業系統配置,以減少記憶體漏洞,提高駭客的攻擊門檻。

今年出現Prossimo專案,開始推動安全程式語言的廣泛採用

對於NSA的這項建議,根據IT新聞媒體The Register的,Acronis資安長Kevin Reed認為,NSA正在做正確的事情,但他懷疑這是否會有立竿見影的效果,因為多年來使用C/C++撰寫的程式碼數量龐大,即便明天就開始改用Rust與Go,也需要幾十年才能清理這個爛攤子。

而且,真的能夠如此順利推動嗎?微軟Azure技術長Mark Russinovich在今年9月就曾針對這樣的議題,於社群媒體推特發表了看法。他指出,在安全性與可靠性考量下,現在該停用C/C++開發任何新專案,並建議改用Rust。但在此則貼文回應中,有相當多開發者持反對意見,畢竟C與C++仍是熱門程式語言。

但無論如何,記憶體安全問題已不容忽視。對照MITRE公布的2022年25大常見CWE通用弱點列表名單,我們可以發現,記憶體越界寫入(Out of Bounds Writes),記憶體越界讀取(Out of Bounds Reads),以及使用已釋放的記憶體(Use after Free),都在前七名內,尤其是記憶體越界寫入,持續居於第一嚴重的地位,而這樣居高不下的排名,也呼應多數軟體漏洞可直接歸因於缺乏記憶體安全性的推論。

而在今年5月Linux基金會與OpenSSF發布的「開源軟體安全動員計畫」白皮書中,其實已經針對此問題提出對策,此計畫的主要目標,是減少記憶體安全性漏洞的數量。

首先,他們希望,在網際網路上最關鍵的軟體,能夠遠離C/C++等不安全的程式語言,並強調會優先升級對安全最敏感的元件,其次,系統級程式碼的工具需要受到更大的關注,因為這些是生態系統中最普遍與最脆弱的軟體,也最有可能是以不安全的系統程式語言所寫成,而產生了資安漏洞。

同時,這項戰略的執行,將透過非營利組織網際網路安全小組(ISRG)的Prossimo專案來推動。目前這項計畫鎖定那些面向?例如,針對用C語言撰寫的Linux Kernel,如今已有Rust for Linux專案啟動;針對用C語言撰寫的OpenSSL,在替代方案上,也有一套名為Rustls的開放軟體專案正在發展。其餘面向還包括:網路時間協定NTP、Apache httpd的mod_tls模組、Trust-DNS、網路傳輸程式curl,Prossimo專案將針對相關工具進行投資,目的是讓建構更安全軟體變得簡單。

而在這些消息中,我們可以發現支持採用Rust的聲浪最大,而且,許多大型企業與開源專案也都嘗試用Rust來撰寫,像是Google的Android與Chrome、Amazon的虛擬化技術Firecracker等。

無論如何,因應軟體開發造成的記憶體安全性問題,已不只是口頭呼籲,而是有所行動,再加入美國NSA難得表態力挺使用安全程式語言,使得這項一再受到討論與思考的問題,出現了更多大幅改善的機會。

🍎たったひとつの真実見抜く、見た目は大人、頭脳は子供、その名は名馬鹿ヒカル!🍏