問:
我剛剛意識到在任何語言裡,當你把密碼儲存到一個變量裡,它将以文本的形式存放在記憶體裡。
我認為作業系統将發揮作用,禁止程序互相通路彼此配置設定的記憶體。但是我也認為這多少有些不是靠譜的做法。是以我想知道這是不是真正安全的,是否有更加安全的存儲密碼的方法,來確定外部程序不能通路它們。
我沒有指定作業系統或者語言,因為我的問題是非常普遍的。這更像是一個計算機常識問題、而不是具體的問題。
答:
你點到了一個痛處……
從曆史上講,計算機是大型機,允許許多不同的使用者在相同的實體機上建立會話和程序。類Unix系統(比如Linux),還有VMS和其相關親戚(和包括所有NT、和此後的2000,XP, Vista, 7, 8…… 的Windows家族,),設計之初是為了支援大型機模型。這樣,硬體提供權限級别。作業系統最重要的部分是核心,它以最高權限級别運作(是的,我知道對于虛拟化有些微妙),并管理權限級别。應用程式以較低級别運作,核心禁止它讀、寫其他應用程式的記憶體。應用程式按頁(page,通常4或8KB)從核心獲得RAM。如果一個應用程式試圖通路另一個應用程式的頁,核心就會阻止它,并且受到嚴重懲罰(“segmentation fault”, “general protection fault”)。
當一個應用程式不再需要頁(特别是在該應用程式還存在的時候)時,核心會控制該頁,可能會分給另一個應用程式。現代作業系統在使用這些頁的時候,會“清空”(blank)該頁,這裡的“清空”指“用零填充”,進而阻止資料從一個程序洩露到另一個程序。注意,Windows 95/98/Millenium沒有清空頁,洩露有時候會出現……但是,這些作業系統是針對單台機器的單個使用者的。
當然,有很多繞過核心的方法:應用程式有一些方式來擷取“足夠的權限”(沒有上面權限高的、同種類型權限)。Linux系統有
ptrace,核心允許一個程序通過ptrace()讀寫另一個程序的記憶體,此時這兩個程序需要運作在同一個使用者ID下,或者運作ptrace()程序的是“root”使用者。相似的功能也存在于Windows。
底線是RAM裡的密碼沒有作業系統允許的安全。按照定義,在程序記憶體裡存儲一些機密資料有個前提,就是你相信作業系統不會把資料給第三方。作業系統是你的朋友,因為如果它是敵人,那麼你就失去了一切。
有意思的環節到了。既然作業系統負責程序的隔離,還是有很多人試着找到了穿透防護的辦法。這裡是他們找到的有趣的辦法……
應用程式看到的“RAM”不是真正需要的“記憶體”。核心是假象的管理者,配置設定實際不存在的頁。假象是通過通過磁盤上的專用空間來交換RAM内容,磁盤上的空閑空間是相當大的;這被稱為
虛拟記憶體。應用程式無需關心,因為核心會根據需要取回這些頁(當然,磁盤比RAM慢很多)。不幸的後果是,一些資料,特别是位于RAM中的資料,使得RAM變成 資料被覆寫之前的 實體載體。尤其是當電源被切斷時,它仍然呆在那裡。當壞家夥搞走這台機器,随後就能擷取資料了。或者機器退役後在eBay賣出,系統管理者忘記了徹底清除磁盤内容。
Linux提供了一個
mlock的系統調用來阻止核心把某些特定的頁發送到swap區。既然鎖住RAM裡的頁能夠大大減少其他程序擷取RAM資源的情況,那麼你需要一些權限(還是root)來使用這個功能。
惱人的地方在于,追蹤真正儲存在RAM裡的密碼必然是不太容易的。做為一個程式員,你是通過程式設計語言提供的抽象方式來通路RAM的。尤其是使用
垃圾回收的程式設計語言會明顯地複制RAM裡的對象(因為它對很多GC算法有幫助)。大多數程式設計語言就是這樣被影響的(像Java, C#/.NET, Javascript, PHP……清單幾乎沒有盡頭)。
hibernation似乎為了複仇帶來了同樣的問題。本來,hibernation必須把整個RAM寫回磁盤——包括mlock()涉及的頁,甚至CPU注冊的内容。為了避免hibernation洩露資料,你不得不采取像加密整個磁盤之類的猛烈的措施——這自然意味着隻要你喚醒機器,就可以鍵入解除鎖定的密碼。
大型機模型假定它能夠運作一些彼此友好的程序,且保持極好的和平和隔離。現代硬體加劇了這一難度。當兩個程序運作在同一個CPU時,它們共享資源,包括緩存記憶體;記憶體通路比緩存之外的任何地方都要快,但是緩存大小十分有限。這催生了一個程序使用來自于另一個程序的
恢複密鑰。使用其他類緩存的資源變體也有了,比如CPU裡的分支預測(branch prediction)。随着對高度機密的、集中于密鑰的研究,它能夠真正應用于任何資料。
還有種情況,顯示卡能夠做
直接記憶體存取(Direct Memory Access,DMA)【注1】。DMA是否不會被濫用去讀寫其他程序的記憶體 取決于 文檔不全的硬體、閉源的驅動程式和核心是如何協作確定合适的通路控制的。我不會為此賭我一件上次穿過的襯衣的……
結論:是的,當你在RAM存放密碼時,你是相信作業系統會確定機密的。是的,這個任務很艱巨,甚至在現代系統上是不可能的。如果你的資料高度機密,你就不應該使用大型機模型,也不要允許潛在友好的實體在你的機器上運作代碼。(順便說一句,這意味着托管的虛拟主機和雲計算根本是不安全的。如果你對安全比較在意,請使用專有硬體。)
注1:DMA:
http://zh.wikipedia.org/zh-cn/%E7%9B%B4%E6%8E%A5%E8%A8%98%E6%86%B6%E9%AB%94%E5%AD%98%E5%8F%96 http://zh.wikipedia.org/zh-cn/%E7%9B%B4%E6%8E%A5%E8%A8%98%E6%86%B6%E9%AB%94%E5%AD%98%E5%8F%96