我剛剛意識到,以任何一種語言,當您將密碼保存在變量中時,密碼都會以純文本格式存儲在內存中。
我認為操作系統可以完成其工作,並且禁止進程訪問彼此分配的內存。但是我也認為這是可以繞開的。因此,我想知道它是否真的安全,是否有一種更安全的方法來存儲密碼以確保外部進程無法訪問它們。
我沒有指定操作系統或語言,因為我的問題是很一般。這是一個計算機素養問題,而不是一個特定目的的問題。
我剛剛意識到,以任何一種語言,當您將密碼保存在變量中時,密碼都會以純文本格式存儲在內存中。
我認為操作系統可以完成其工作,並且禁止進程訪問彼此分配的內存。但是我也認為這是可以繞開的。因此,我想知道它是否真的安全,是否有一種更安全的方法來存儲密碼以確保外部進程無法訪問它們。
我沒有指定操作系統或語言,因為我的問題是很一般。這是一個計算機素養問題,而不是一個特定目的的問題。
您碰到了一個痛處...
從歷史上看,計算機是大型機,許多不同的用戶在其中啟動會話和處理同一台物理機器。構造了類似Unix的系統(例如Linux),還包括VMS及其親戚(該家族包括NT系列的所有Windows,因此包含2000,XP,Vista,7、8 ...),以支持大型機模型。
因此,硬件提供了特權級別。操作系統的核心部分是內核,它以最高特權級別運行(是的,我知道虛擬化方面存在一些細微問題),並且管理特權級別。應用程序以較低級別運行,並且被內核強制阻止讀取或寫入彼此的內存。應用程序從內核通過 pages (通常為4或8 kB)獲得RAM。試圖訪問屬於另一個應用程序的頁面的應用程序被內核阻止,並受到嚴厲懲罰(“分段錯誤”,“一般保護錯誤” ...)。
當不再需要某個應用程序時一個頁面(尤其是在應用程序退出時),內核將控制該頁面並將其交給另一個進程。現代操作系統在將頁面退還之前先將其“空白”,其中“空白”表示“用零填充”。這樣可以防止數據從一個進程洩漏到另一個進程。請注意,Windows 95/98 / Millenium不會空白頁,可能會發生洩漏……但是這些操作系統是針對每台計算機的單個用戶使用的。
當然,有一些方法可以避免內核的憤怒:具有“足夠特權”(與上面特權不同的特權)的應用程序可以使用一些入口。在Linux系統上,這是 ptrace()。內核允許一個進程通過ptrace()讀寫另一個進程的內存,前提是兩個進程都在相同的用戶ID下運行,或者執行ptrace()的進程是“根”進程。 Windows中存在類似的功能。
最重要的是,RAM中的密碼並不比操作系統所允許的安全。根據定義,通過將一些機密數據存儲在內存中在一個過程中,您相信操作系統不會將其提供給第三方。操作系統是您的朋友,因為如果操作系統是敵人,那麼您將徹底迷失方向。
現在是最有趣的部分。由於操作系統強制執行流程分離,因此許多人試圖找到突破這些防禦的方法。他們發現了一些有趣的東西...
應用程序看到的“ RAM”不一定是真正的“內存”。內核是一種幻覺的掌握者,它給出的頁面不一定存在。通過將RAM內容與磁盤上的專用空間交換來保持這種錯覺,在磁盤上存在大量可用空間。這稱為虛擬內存。應用程序不需要意識到這一點,因為內核會在需要時帶回頁面(但是,磁盤比RAM慢得多)。不幸的結果是,據稱保存在 RAM 中的某些數據將其保存到物理介質中,直到被覆蓋為止。特別是如果斷電,它將停留在該處。這允許攻擊者在壞人抓住機器並帶走機器的情況下進行攻擊,以便稍後檢查數據。否則,當一台計算機退役並在eBay上出售時,如果系統管理員忘記擦除磁盤內容,則可能會發生洩漏。
Linux提供了一個名為 mlock()的系統,該系統可防止內核將某些特定的頁面發送到交換空間。由於將頁面鎖定在RAM中可能會耗盡其他過程可用的RAM資源,因此您需要一些特權(再次是root用戶)才能使用此功能。
一種加劇的情況是,跟踪您的位置不一定很容易密碼確實在RAM中。作為程序員,您可以通過編程語言提供的抽象來訪問RAM。特別是,使用垃圾收集的編程語言可以透明地複制RAM中的對象(因為它確實對許多GC算法有幫助)。因此,大多數編程語言都會受到影響(例如Java,C#/。NET,Javascript,PHP,...幾乎是無止境的)。
休眠帶回報復的相同問題。從本質上講,休眠方式必須將整個RAM寫入磁盤-這可能包括被鎖住的頁面,甚至包括CPU寄存器的內容。為了避免由於休眠而造成的洩漏,您必須採取諸如加密整個磁盤之類的嚴厲措施-這自然意味著在您喚醒計算機時都輸入了解鎖密碼。
大型機模型假設它 可以運行彼此敵對的幾個進程,但仍保持完美的和平與孤立。現代硬件使這一點變得非常困難。當兩個進程在同一CPU上運行時,它們共享一些資源,包括緩存。緩存中的內存訪問比其他地方快得多,但是緩存的大小非常有限。這已被利用來從一個進程中恢復另一個進程所使用的加密密鑰。已開發出使用其他類似緩存的資源的變體,例如CPU中的分支預測。儘管對該主題的研究集中於加密密鑰,這是高價值秘密,但它實際上可以應用於任何數據。
類似地,視頻卡可以進行直接內存訪問。是否可以濫用DMA來從其他進程讀取或寫入內存,取決於未記錄的硬件,閉源驅動程序和內核如何協作以實施適當的訪問控制。我不會打賭我的最後一件襯衫……
結論:是的,當您將密碼存儲在RAM中時,您信任該操作系統以保持機密性。是的,任務很艱鉅,在現代系統上幾乎是不可能的。如果某些數據是高度機密的,則您實際上不應該使用大型機模型,也不要允許潛在敵對實體在計算機上運行其代碼。
(順便說一下,這意味著託管虛擬機和雲計算不能最終保證安全。如果您對安全性很重視,請使用專用硬件。)
我認為操作系統可以完成他的工作,並避免進程訪問其他人分配的內存。但是我認為這是可行的。
是的,可以訪問另一個進程的內存。在Windows上,這等於具有 SE_DEBUG_PRIVILEGE
並使用 ReadProcessMemory()
來提取所需的信息。
您可以從Windows驅動程序執行相同的操作,儘管由於當前內存分頁到下半部分會有些複雜,因此很難正確使用。
無論哪種情況,您都需要具有訪問權限一個管理帳戶,一個錯誤分配了 SE_DEBUG_PRIVILEGE
的進程,或一個具有這種特權的,可以被說服做您所需的特權的進程。
因此,歸結為確保沒有人可以升級以獲得這些特權。實際上,我們確保只有受信任的用戶才能擁有這些特權。如果您有權訪問管理帳戶,則可以很容易地從另一個帳戶的進程的內存中直接讀取密碼。
在Linux下,您可以使用 ptrace( )
和 PTRACE_PEEK_DATA
選項。
您可能會問為什麼這些功能首先存在?實際上,它們在調試過程中非常方便。可以想像,這是管理員用戶可能希望做的事情。相比之下,普通用戶則不需要,而且應該彼此隔離。
這就是為什麼人們建議一段時間以來,以Administrator帳戶運行所有內容通常不是一個好主意的原因。 / p>
我在消費電子領域工作,這裡的安全性與服務器環境有些不同。在這裡,我們必須假設該產品處於敵對環境中。因此,出於訂戶管理的目的,密鑰是安全的。第一道防線是SoC具有隱藏的寄存器,即使操作系統實際上也無法訪問這些寄存器,它們在製造時就被燒壞了,並且熔斷了保險絲以阻止訪問。同樣,我們自己也看不到密鑰,因為這在生產現場是不安全的,相反,它們被預先包裝了一個我們不知道的批量密鑰,只有芯片供應商和創建密鑰的人才知道(主可以在芯片中使用後銷毀密鑰)。一旦芯片上裝有機密信息,就可以將其鎖定,並且永遠不會*被解鎖。
如果您無法訪問密鑰,那麼如何解密內容呢?通過SoC上的加密協處理器,您可以加載密鑰位置,而無需實際知道其中的值。您也永遠不會看到加密處理器的微代碼,因為即使在製造時,您也無法注入任何東西。
如果您的密鑰或證書不適合大量的芯片寄存器,則必須將它們存儲在RAM和/或 NVM中,但是由於使用了加密處理器您無需公開這些值。 RAM或NVM本身可以用芯片來加密,而密鑰本身並不為人所知。
與計算機不同,安全嵌入式系統還具有一定的物理安全性。 RAM連接軌道不允許位於PCB表面(“埋孔”)。這是因為,如果RAM中有明確的元素,則需要限制訪問,則可以減慢或凍結CPU,然後探測RAM。
最後,對於智能卡而言,可以攔截SoC和卡之間的交易。這就是所謂的“卡共享”,解決方案是對卡和SoC之間的交易進行加密,並將它們彼此綁定,以使它們無法交換或共享。
我知道DRM / content安全對於Internet上的某些人來說並不受歡迎,但是我想我會分享來自具有某些特定安全要求的行業的一些高級概念。
*理論上。
在Linux平台上正在進行一些工作,以禁止超級用戶訪問正在運行的進程的內存。使用SELinux,您可以從Fedora 17開始: SELinux Deny Ptrace。
您使用的是哪種語言/平台?
如果是.NET,請檢出 PasswordBox控件和 SecureString類。
SecureString類表示一種將密碼存儲在內存中而不讓任何人都可以訪問的方法,即使是偷偷窺視應用程序內存的黑客也是如此。包含SecureString,因此您可以確保端到端的密碼安全。
否,不應將以明文形式存儲在RAM中的密碼視為安全密碼。通常,在具有直接訪問接口(例如FireWire,ExpressCard和Thunderbolt)的x86和x86-64體系結構上,這些接口可用於繞過操作系統內存保護,從而從內存中獲取純文本密碼。
使用FireWire獲得純文本密碼並非只是理論上的攻擊。現在正在出售軟件以獲取BitLocker,PGP和TrueCrypt加密磁盤的純文本密碼 ElcomSoft解密BitLocker,PGP和TrueCrypt容器
security.stackexchange上有一個單獨的線程如何緩解DMA基本攻擊在Linux下安全禁用火線/雷電,修補DMA暴露。微軟也有一個知識庫文章,以緩解通過BitLocker上的Firewire和Thunderbolt進行的攻擊阻止SBP-2驅動程序和Thunderbolt控制器以減少對BitLocker的1394 DMA和Thunderbolt DMA威脅
更多有關此攻擊的詳細信息,請參見Wikipedia DMA攻擊。
除了所有利用操作系統漏洞的軟件攻擊之外,如果攻擊者可以物理訪問您的計算機,他們還可以直接從內存中讀取密鑰。
您提出了一個有效的問題,而實際上,這通常在與安全性相關的軟件中得到解決。當不再需要諸如密鑰之類的敏感對象時,某些程序將不會簡單地將內存交還給內存管理庫或操作系統,而是先通過覆蓋敏感位來消除它們。
當然,有些程序需要持續按住鍵。例如 ssh-agent
。因此,這些程序容易受到攻擊。如果您是多用戶計算機上的普通用戶,則 ssh-agent
的動態內存將受到具有root privs並且可以查看計算機內存任何部分的任何人的攻擊。
無論如何,即使短暫使用鍵的程序仍然存在漏洞窗口。一微秒可能是CPU時間的永恆。惡意的超級用戶甚至可以在某些指令上無限期地暫停程序,而該程序在內存中的某處具有純文本格式的敏感數據。
因此,根據經驗,不要執行任何對安全性敏感的操作在計算機上進行計算(如果該計算機具有您不信任的任何用戶或軟件)以及不信任的操作系統,以防止這些用戶或軟件提升其特權,以便他們可以窺視您的密鑰或明文數據。
使用任何安全客戶端時,您都信任該程序以及它的整個平台,直到整個硬件平台以及預安裝或以後安裝的每個程序中的每條機器指令為止。
(所謂的“可信計算”並不能解決這個問題;它只是改變了惡棍的身份。)
即使密鑰是加密的,鱈魚啟動攻擊也可以檢索您的密碼:查看此正在進行的冷啟動攻擊的視頻。. http://www.youtube.com/watch?v=JDaicPIgn9U
除非您有時間閱讀所有源代碼並確認不存在漏洞利用程序,否則一定要有一定程度的信任才能保證操作系統和應用程序運行的安全性。如果您有那個時間,就不需要信任。但這是不可能的。如果可能的話,最好在一台機器上運行專有項目,並在另一台機器上運行所有必須信任的內容。與基於信仰的解決方案相比,物理隔離可以很好地解決問題。
需要做一些相關的研究,以確保即使超級用戶也無法訪問存儲在某些其他進程的內存中的機密。我從未真正完成過這項工作,因此這只是一個起點。這並不能阻止任何物理攻擊,例如冷啟動攻擊。
這不能解決您的問題,儘管您可以使用一種技巧來最大程度地減少將密碼或其他機密存儲在內存中的時間,然後再將其清零。
請小心使用一種保證您正在寫入相同的內存,而不是分配具有不同值的新對象。例如,在Java中,您可以使用 byte []
而不是 String
來保存秘密。
鑑於這可能適用於具有不同保護級別的許多操作系統,請記住以下幾點: