為了避免記憶體攻擊,美國國家安全局提倡 Rust、C#、Go、Java、Ruby 和 Swift,但將 C 和 C++ 置於一邊

為了避免記憶體攻擊,美國國家安全局提倡 Rust、C#、Go、Java、Ruby 和 Swift,但將 C 和 C++ 置於一邊

對於許多開發人員來說,這可能意味著轉向 C#、Go、Java、Ruby、Rust 和 Swift。

最後更新 2022/11/16 上午7:31
沙漠尽头的狼
預計閱讀 18 分鐘
分類
分享
標籤
.NET C# Java Go 安全

先丟出美國國家安全局的一篇文章:NSA Releases Guidance on How to Protect Against Software Memory Safety Issues

本文翻譯自兩篇文章,第一篇是對美國國家安全局在「軟體記憶體安全」網路安全資訊表的解讀,第二篇是普及什麼是記憶體安全,為什麼它很重要?

第一篇 為了避免記憶體攻擊,美國國家安全局提倡 Rust、C#、Go、Java、Ruby 和 Swift,但將 C 和 C++ 置於一邊

本文來自翻譯(谷歌翻譯加持)。

原文作者: Liam Tung

原文標題:NSA to developers: Think about switching from C and C++ to a memory safe programming language

原文連結:https://www.zdnet.com/article/nsa-to-developers-think-about-switching-from-c-and-cpp-to-a-memory-safe-programming-language/

Image: Getty Images/iStockphoto

對於許多開發人員來說,這可能意味著轉向 C#、Go、Java、Ruby、Rust 和 Swift。

美國國家安全局 (NSA) 敦促開發人員轉向記憶體安全語言——例如 C#、Go、Java、Ruby、Rust 和 Swift——以保護他們的程式碼免受遠端程式碼執行或其他駭客攻擊。

在上面提到的語言中,Java 是企業和 Android 應用程式開發中使用最廣泛的語言,而 Swift 是前 10 名語言,部分歸功於 iOS 應用程式開發。在系統程式設計中,人們越來越關注 Rust 作為 C 和 C++ 的替代品。

「美國國家安全局建議組織考慮在可能的情況下從提供很少或不提供內在記憶體保護的程式語言(例如 C/C++)到記憶體安全語言的戰略轉變。記憶體安全語言的一些範例包括 C#、Go、Java、Ruby 和 Swift。」美國國家安全局說。

該間諜機構援引 Google 和微軟最近的研究表明,他們 70% 的安全問題(分別在 Chrome 和 Windows 中)與記憶體相關,其中許多是使用 C 和 C++ 的結果,它們更容易出現基於記憶體的漏洞。

另外: 網路安全、雲端和編碼:為什麼這三項技能將在 2023 年引領需求

美國國家安全局在「軟體記憶體安全」網路安全資訊表中指出:「惡意網路行為者可以利用這些漏洞進行遠端程式碼執行或其他不利影響,這通常會危及裝置並成為大規模網路入侵的第一步。」

「C 和 C++ 等常用語言在記憶體管理方面提供了很大的自由度和靈活性,同時嚴重依賴程式設計師對記憶體參考執行所需的檢查。」

因此,該機構建議盡可能使用記憶體安全語言,無論是用於應用程式開發還是系統程式設計。

「NSA 建議盡可能使用記憶體安全語言,」它指出。

雖然大多數資訊安全專家都熟悉這場關於記憶體安全語言的爭論,但也許並非所有開發人員都熟悉。不過,考慮到這是一個存在了幾十年的問題,也許他們應該這樣做,正如 Java 的創建者 James Gosling 最近在一次關於如何以及為什麼創建 Java 的討論中指出的那樣。

如果有的話,NSA 文件為開發人員提供了一個清晰、通俗易懂的語言解釋,說明了轉向記憶體安全語言背後的技術原因。在記憶體安全方面討論最多的語言可能是 Rust,它是 C 和 C++ 的「替代品」的主要候選語言。

繼 Android 開源專案之後,Linux 核心 最近將 Rust 作為 C 的第二語言引入。這些專案不會替換舊的 C/C++ 程式碼,但會更喜歡 Rust 作為新程式碼。此外,Microsoft Azure CTO Mark Russinovich 最近呼籲所有開發人員在所有新專案中使用 Rust 而不是 C 和 C++

「透過利用這些類型的記憶體問題,不受軟體使用正常預期約束的惡意行為者可能會發現他們可以向程式輸入不尋常的輸入,導致以意想不到的方式存取、寫入、分配或釋放記憶體,」美國國家安全局解釋。

但是——正如專家在關於 Rust 和 C/C++ 的辯論中指出的那樣 ——美國國家安全局警告說,簡單地使用記憶體安全語言並不能預設排除將記憶體錯誤引入軟體。此外,語言通常允許不是用記憶體安全語言編寫的庫。

「即使使用記憶體安全語言,記憶體管理也不完全是記憶體安全的。大多數記憶體安全語言都認識到軟體有時需要執行不安全的記憶體管理功能才能完成某些任務。因此,可以使用被認為是非記憶體安全並允許程式設計師執行可能不安全的記憶體管理任務,」美國國家安全局說。

「一些語言要求任何記憶體不安全的東西都被顯式註解,以使程式設計師和程式的任何審閱者意識到它是不安全的。記憶體安全語言也可以使用以非記憶體安全語言編寫的庫,因此可以包含不安全的記憶體功能。儘管這些包含記憶體不安全機制的方法顛覆了固有的記憶體安全性,但它們有助於定位可能存在記憶體問題的位置,從而允許對這些程式碼部分進行額外的審查。

另外: 網路安全:這些是 2023 年需要擔心的新事物

NSA 指出,某些記憶體安全語言可能會以效能成本為代價,這需要開發人員學習一門新語言。它還指出開發人員可以採取一些措施來強化非記憶體安全語言。例如, Google 的 Chrome 團隊正在探索多種強化 C++ 的方法,但這些方法也會帶來效能開銷。在可預見的未來,C++ 將保留在 Chrome 的程式碼庫中。

NSA 建議進行靜態和動態應用程式安全測試以發現記憶體問題。它還建議探索記憶體強化方法,例如 Control Flow Guard (CFG),這將限制程式碼的執行位置。同樣,建議使用位址空間佈局隨機化 (ASLR) 和資料執行保護 (DEP)。

第二篇 什麼是記憶體安全,為什麼它很重要?

本文來自翻譯(谷歌翻譯加持)。

出處:https://www.memorysafety.org

原文標題:What is memory safety and why does it matter?

原文連結:https://www.memorysafety.org/docs/memory-safety/

記憶體安全是一些程式語言的一個屬性,它可以防止程式設計師引入與記憶體使用方式相關的某些類型的錯誤。由於記憶體安全漏洞通常是安全問題,因此記憶體安全語言比非記憶體安全語言更安全。

記憶體安全語言包括 Rust、Go、C#、Java、Swift、Python 和 JavaScript。記憶體不安全的語言包括 C、C++ 和組合語言。

記憶體安全漏洞的類型

為了開始理解記憶體安全漏洞,我們將考慮一個為許多用戶維護待辦事項列表的應用程式範例。我們將了解幾種最常見的記憶體安全錯誤類型,它們可能發生在記憶體不安全的程式中。

越界讀寫

如果我們有一個包含十項的待辦事項列表,而我們要求第十一項,會發生什麼?顯然我們應該收到某種錯誤。如果我們要求否定的第一項,我們也應該得到一個錯誤。

在這些情況下,記憶體不安全的語言可能允許程式設計師讀取列表的有效內容之前或之後恰好存在的任何記憶體內容。這稱為越界讀取。列表第一項之前的記憶體可能是其他人列表的最後一項。列表最後一項之後的記憶體可能是其他人列表的第一項。存取此記憶體將是一個嚴重的安全漏洞!程式設計師可以透過仔細檢查他們要求的項目的索引與列表的長度來防止越界讀取,但是程式設計師會犯錯誤。最好使用一種記憶體安全語言,預設情況下可以保護您和您的用戶免受此類錯誤的侵害。

在記憶體安全語言中,我們會在編譯時出錯或在執行時崩潰。程式崩潰看似嚴重,但總比讓用戶竊取彼此的資料要好!

一個密切相關的漏洞是越界寫入。在這種情況下,假設我們試圖更改待辦事項列表中的第十一項或否定的第一項。現在我們正在改變別人的待辦事項清單!

釋放後使用

想像一下,我們刪除了一個待辦事項列表,然後請求該列表的第一項。顯然我們應該收到一個錯誤,因為我們不應該能夠從已刪除的列表中獲取項目。記憶體不安全的語言允許程式獲取他們已經完成的記憶體,現在可以將其用於其他用途。記憶體中的位置現在可能包含其他人的待辦事項列表!這稱為釋放後使用漏洞。

記憶體安全漏洞有多普遍?

極其。最近的一項研究發現,iOS 和 macOS 中 60-70% 的漏洞是記憶體安全漏洞。Microsoft 估計,在過去十年中,其產品中的所有漏洞中有 70% 是記憶體安全問題。Google 估計 90% 的 Android 漏洞都是記憶體安全問題。對被發現廣泛被利用的 0-day 的分析發現,超過 80% 的被利用漏洞是記憶體安全問題1。

2003 年的Slammer 蠕蟲(這是一種專門衡量軟體漏洞的方法,它不包括諸如憑證網路釣魚之類的非常普遍的事情。)是緩衝區溢位(越界寫入)。WannaCry(越界寫入)也是如此。針對 iPhone的Trident 漏洞利用了三個不同的記憶體安全漏洞(兩個釋放後使用和一個越界讀取)。HeartBleed是記憶體安全問題(越界讀取)。Android 上的Stagefright也是如此(越界寫入)。glibc 中的Ghost漏洞?你打賭(越界寫)。

由於 C 和 C++ 不是記憶體安全的,因此這些漏洞以及利用其他漏洞成為可能。編寫大量 C 和 C++ 的組織不可避免地會產生大量漏洞,這些漏洞可直接歸因於缺乏記憶體安全性。這些弱點被利用,給醫院持不同政見者衛生政策專家帶來危險。使用 C 和 C++對社會不利,對您的聲譽不利,對您的客戶不利。

與記憶體不安全的語言相關的還有哪些其他問題?

記憶體不安全的語言也會對穩定性、開發人員生產力和應用程式效能產生負面影響。

由於記憶體不安全的語言往往會出現更多錯誤和崩潰,因此會極大地影響應用程式的穩定性。即使崩潰不是安全敏感的,它們對用戶來說仍然是非常糟糕的體驗。

更糟糕的是,開發人員很難追蹤到這些錯誤。記憶體損壞通常會導致崩潰發生在距離錯誤實際位置很遠的地方。當涉及多執行緒時,執行緒執行時間的微小差異可能會觸發其他錯誤,從而導致更難重現錯誤。結果是開發人員通常需要盯著崩潰報告看幾個小時才能確定記憶體損壞錯誤的原因。這些錯誤可能幾個月都沒有修復,開發人員完全相信存在錯誤,但不知道如何在發現其原因和修復方面取得進展。

最後,還有效能。在過去的幾十年裡,人們可以指望 CPU 每一兩年都變得更快。這已不再是這種情況。相反,CPU 現在帶有更多核心。為了利用額外的核心,開發人員需要編寫多執行緒程式碼。

不幸的是,多執行緒加劇了與缺乏記憶體安全相關的問題,因此,在 C 和 C++ 中利用多核 CPU 的努力通常是棘手的。例如——在最終(成功)用多執行緒 Rust 重寫系統之前,Mozilla 多次嘗試將多執行緒引入 Firefox 的 C++ CSS 子系統,但均以失敗告終。

正確的前進道路是什麼?

使用記憶體安全語言!有很多很棒的可供選擇。編寫作業系統核心或 Web 瀏覽器?考慮Rust!為 iOS 和 macOS 構建?Swift可以勝任。網路伺服器?Go 是個不錯的選擇。這些只是幾個例子,還有許多其他優秀的記憶體安全語言可供選擇(以及許多其他精彩的用例配對!)。

更改您的組織使用的程式語言並非輕而易舉。這意味著改變你在招募時尋找的技能,這意味著對你的員工進行再培訓,這意味著重寫大量程式碼。儘管如此,我們相信從長遠來看這是必需的,因此我們想說明為什麼採用新程式語言的替代方案沒有成功。

如果我們理所當然地認為使用不安全的語言會產生一些漏洞,那麼我們想問的問題是:我們是否可以採取一些技術來降低這種風險,而不用強迫自己完全改變程式語言?答案是肯定的。並非所有用不安全語言編寫的專案都同樣不安全和不可靠。

一些可以降低使用不安全語言風險的做法是:

  • 使用一些現代 C++ 慣用語可以幫助產生更安全可靠的程式碼
  • 使用fuzzerssanitizers幫助在將錯誤投入生產之前找到它們
  • 使用漏洞利用緩解措施來幫助增加利用漏洞的難度
  • 權限分離,即使漏洞被利用,爆炸半徑也更小

這些做法有意義地降低了使用不安全語言的風險,如果我們未能說服您更換語言,而您打算繼續編寫 C 和 C++,那麼採用這些做法勢在必行。不幸的是,它們也嚴重不足。

瀏覽器和作業系統開發人員是開發現代 C++ 慣用語、fuzzerssanitizers、漏洞利用緩解和權限分離技術的最前沿人員——正是我們在開始時透過有關記憶體安全問題普遍性的統計數據強調的群體。儘管這些團隊在這些技術上進行了投資,但他們使用不安全的語言卻拖累了他們。在大型駭客大賽pwn2own上,2019年這些產品被利用的漏洞中有一半以上是由於缺乏記憶體安全,除了一個例外,每一次成功的攻擊都至少利用了一個記憶體安全漏洞。

放棄 C 和 C++ 真的可行嗎?

希望到目前為止,我們已經讓您相信,像 C 和 C++ 這樣的不安全語言是我們產品中大量不安全的根本原因,並且儘管您可以採取一些措施來降低風險,但您無法接近消除它。所有這些可能仍然讓你覺得改變你使用的程式語言,產生數百萬行程式碼,是一個壓倒性的巨大任務。透過將其分解為可管理的部分,我們可以開始取得進展——我們的目標不是大爆炸式地重寫世界,而是在降低風險方面取得進展。

首先是全新的專案。對於這些,您可以選擇簡單地使用記憶體安全語言。這些專案的風險最低,因為您不需要從重寫任何程式碼開始,儘管像這樣的專案通常確實需要改進測試或部署基礎設施以支援新的程式語言。這是 ChromeOS 的 CrosVM(作業系統的全新元件)所採用的方法。

如果您沒有新專案,下一個尋找機會使用記憶體安全語言的地方是現有專案的新元件。一些記憶體安全語言對與 C 和 C++ 程式碼庫(例如 Rust 和 Swift)的互操作提供了一流的支援。這需要稍高的初始投資,因為它需要整合到建構系統中,以及使用新語言為需要跨越兩種語言之間的邊界傳遞的物件和資料建構抽象。當WebAuthn作為 Firefox 的一個新元件實現時,以及一個支援在 Rust 中編寫 Linux 核心模組的專案,就成功地使用了這種策略。

前兩種方法的共同點是它們都處理新程式碼。這具有與現有程式碼定義明確的交互點的優勢,並且無需重寫任何內容即可開始工作。它還為您提供了止血的機會:沒有使用不安全語言的新元件,我們將逐步處理現有程式碼。對於沒有任何自然的新元件來開始使用記憶體安全語言的專案,採用更具挑戰性。

在這種情況下,您需要尋找一些現有元件以將不安全語言重寫為安全語言。最好是您選擇的元件是您已經考慮重寫的元件:可能是為了效能、安全性,或者是因為程式碼太難維護。你應該嘗試為你的第一次記憶體安全重寫選擇範圍盡可能小的東西,以幫助專案成功並盡快發布;這有助於將重寫中固有的風險降至最低。Stylo,用 Rust 重寫了 Firefox 的 CSS 引擎,是這種方法的一個成功例子。

無論哪種方法最適合您的組織,都需要牢記一些事項以最大化成功的機會。首先是確保你有內部支持者和高級工程師,他們可以使用對許多團隊成員來說都是新的語言提供程式碼審查和指導。這樣做的自然延伸是確保將使用新語言工作的工程師有可用的資源,如書籍、培訓或內部指南。最後,您需要確保新語言擁有與舊語言相同的共享基礎設施,例如建構系統、測試、部署、崩潰報告和其他整合。

結論

採用一種新的程式語言並開始遷移到它的過程並不是一件容易的事。它需要整個組織的規劃、資源配置和最終投資。如果我們不必考慮這些事情,生活會容易得多。不幸的是,對數據的審查清楚地表明,我們根本不能考慮繼續為安全敏感專案使用不安全的語言。

數據一次又一次地證明,當專案使用 C 和 C++ 等不安全語言時,它們就會受到大量安全漏洞的困擾。無論工程師多麼有才華,在權限減少和利用緩解方面的投資有多大,使用記憶體不安全的語言只會導致太多錯誤。這些錯誤大大降低了安全性、穩定性和生產力。

幸運的是,我們不需要滿足於現狀。在過去的幾年中,出現了 C 和 C++ 的絕佳替代品,例如 Rust、Swift 和 Go 等。這意味著我們不必在未來的許多年裡將記憶體損壞漏洞作為一個信天翁掛在脖子上,只要我們選擇不這樣做。我們期待有一天,選擇使用不安全的語言被認為是疏忽大意,因為沒有多因素驗證或沒有加密傳輸中的數據。

感謝亞歷克斯蓋納

經許可,此解釋基於 Alex Gaynor 的部落格文章工程副總裁的記憶體不安全簡介

本文總結

希望大家能從這兩篇譯文中得到些什麼。

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2025/8/13

推薦一款高效能狀態機管理解決方案

在實際軟體開發中,尤其是工業軟體,每一款設備都有複雜的狀態以及狀態之間的切換的功能需求,在這種情況下,如何管理狀態以及狀態之間切換,和對應狀態下的功能控制,成為非常重要的一個問題。

繼續閱讀