轉(zhuǎn)載請注明出處:
https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh/General_Architecture/Sandbox.html
全書地址
Chromium中文文檔 for https://www.chromium.org/developers/design-documents
持續(xù)更新ing,歡迎star
gitbook地址:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//
github地址: https://github.com/ahangchen/Chromium_doc_zh
安全是Chromium最重要的目標(biāo)之一。安全的關(guān)鍵在于理解下面這點:在我們完整地理解了系統(tǒng)在所有可能的輸入組合下表現(xiàn)出的行為之后,我們才能夠真的保證系統(tǒng)安全。對于像Chromium這樣龐大而多樣化的代碼庫,推理它的各個部分可能的行為的組合幾乎是不可能的。沙箱的目標(biāo)是提供這樣一種保證:不論輸入什么,保證一段代碼最終能或不能做的事情。
沙盒利用操作系統(tǒng)提供的安全性,允許不能對計算機做出持久性改變或者訪問持續(xù)變化的信息的代碼的執(zhí)行。沙箱提供的架構(gòu)和具體保證依賴于操作系統(tǒng)。這個文檔覆蓋了Windows實現(xiàn)與一般的設(shè)計。Linux實現(xiàn)和OSX實現(xiàn)也會在這里描述。
如果你不想要閱讀這整個文檔,你可以閱讀Sandbox FAQ。沙箱保護與不保護的內(nèi)容也可以在FAQ中找到。
設(shè)計原則
- 不要重新發(fā)明輪子: 用更好的安全模型擴展操作系統(tǒng)內(nèi)核很有誘惑力。但不要這樣做。讓操作系統(tǒng)在所控制的對象上應(yīng)用它的安全策略。另一方面,創(chuàng)建有自定義安全模型的應(yīng)用程序?qū)蛹墝ο螅ǔ橄螅┦强梢缘摹?/li>
- 最小權(quán)限原則: 這既應(yīng)該用于沙箱代碼也應(yīng)該用于控制沙箱的代碼。換言之,即使用于不能提升權(quán)限到超級用戶,沙箱也需要能夠工作。
- 假定沙盒代碼是惡意代碼: 出于威脅建模的目的,我們認(rèn)為沙箱中的代碼一旦執(zhí)行路徑越過了一些main()函數(shù)的早期調(diào)用,那么它是有害的(即,它會運行有害代碼),實踐中,在第一外部輸入被接收時,或者在進入主循環(huán)前,這就可能發(fā)生。
- 敏感: 非惡意代碼不會嘗試訪問它不能獲得的資源。在這種情況下,沙箱產(chǎn)生的性能影響應(yīng)該接近零。一旦敏感資源需要以一種控制行為訪問時,一點性能損失是必要的。這是在操作系統(tǒng)安全合適事情情況下的常見例子。
- 仿真不是安全: 仿真和虛擬機方案本身不能提供安全。沙箱不會出于安全目的,依賴于代碼仿真,或者代碼轉(zhuǎn)換,或者代碼修復(fù)。
沙箱windows架構(gòu)
Windows沙箱是一種僅用戶模式可用的沙箱。沒有特殊的內(nèi)核模式驅(qū)動,用戶不需要為了沙箱正確運行而成為管理員。沙箱設(shè)計了32位和64位兩種進程,在所有windows7和windows10之間的所有操作系統(tǒng)版本都被測試過。
沙箱在進程級粒度進行運作。凡是需要沙箱化的任何東西需要放到獨立進程里運行。最小化沙箱配置有兩個過程:一個是被成為broker的權(quán)限控制器,以及被稱為target的一個或多個沙箱化進程。在整個文檔和代碼中這兩個詞有著上述兩種精確的內(nèi)涵。沙箱是一個必須被鏈接到broker和target可執(zhí)行程序的靜態(tài)庫。
broker進程
在Chromium中,broker總是瀏覽進程。broker,廣泛概念里,是一個權(quán)限控制器,沙箱進程活動的管理員。broker進程的責(zé)任是:
- 指定每個目標(biāo)進程中的策略
- 生成目標(biāo)進程
- 維護沙箱策略引擎服務(wù)
- 維護沙箱攔截管理器
- 維護沙箱IPC服務(wù)(與target進程的通信)
- 代表目標(biāo)進程執(zhí)行策略允許的操作。
broker應(yīng)該始終比所有它生成的目標(biāo)進程還要活的久。沙箱IPC是一種低級別的機制(與ChromiumIPC機制不同),這些調(diào)用會被策略評估。策略允許的調(diào)用會由broker執(zhí)行,結(jié)果會通過同樣的IPC返回給目標(biāo)進程。攔截管理器是為應(yīng)該通過IPC轉(zhuǎn)發(fā)給broker的windows API調(diào)用提供補丁。
目標(biāo)進程
在Chromium中,渲染器總是target進程,除非瀏覽進程被指定了--no-sandbox命令行參數(shù)。target進程維護所有將在沙箱中允許的代碼,以及沙箱基礎(chǔ)設(shè)施的客戶端:
- 所有代碼沙箱化
- 沙箱IPC客戶端
- 沙箱策略引擎客戶端
- 沙箱攔截
第2,3,4條是沙箱庫的一部分,與需要被沙箱化的代碼關(guān)聯(lián)。
攔截器(也稱為hook)是通過沙箱轉(zhuǎn)發(fā)的Windows API調(diào)用。由broker重新發(fā)出API 調(diào)用,并返回結(jié)果或者干脆終止調(diào)用。攔截器+IPC機制不能提供安全性;它的目的是在沙箱中的代碼因沙箱限制不能修改時,提供兼容性。為了節(jié)省不必要的IPC,在進行IPC調(diào)用前,target中進程策略也會被評估,盡管這不是用作安全保障,但這僅僅是一個速度優(yōu)化。
期望在未來大部分plugin會運行在target進程里。
沙箱限制
在它的核心,沙箱依賴于4個Windows提供的機制:
- 限定的令牌
- Windows工作對象
- Windows桌面對象
- Windows Vista及以上:集成層
這些機制在保護操作系統(tǒng),操作系統(tǒng)的限制,用戶提供的數(shù)據(jù)上相當(dāng)?shù)母咝?,前提是?/p>
- 所有可以安全化的資源都有一個比null更好的安全描述符。換言之,沒有關(guān)鍵資源會有錯誤的安全配置。
- 計算機并未被惡意軟件所損害。
- 第三方軟件不能弱化系統(tǒng)安全。
** 注意:上面具體的措施以及在內(nèi)核外的措施會在下面的“進程輕量化”部分闡述。**
令牌
其他類似的沙箱項目面臨的一個問題是,限制程度應(yīng)當(dāng)如何,才能使得令牌和作業(yè)同時還保持有正常的功能。在Chromium沙箱里,對于Windows XP最嚴(yán)格的令牌如下:
普通組
登錄 SID : 強制
其他所有SID : 僅拒絕, 強制
限制組
S-1-0-0 : 強制
特權(quán)
無
正如上面所述的警告,如果操作系統(tǒng)授予了這樣一個令牌,幾乎不可能找到存在的資源。只要磁盤根目錄有著非空的安全性,即使空安全的文件也不能被訪問。在Vista中,最嚴(yán)格的令牌也是這樣的,但它也包括了完整性級別較低的標(biāo)簽。Chromium渲染器通常使用這種令牌,這意味著渲染器進程使用的大部分資源已經(jīng)由瀏覽器獲取,并且他們的句柄被復(fù)制到了渲染器進程中。
注意,令牌不是從匿名令牌或來賓令牌而來的,它繼承自用戶的令牌,因此與用戶的登錄相關(guān)聯(lián)。因此,系統(tǒng)或域名擁有的任何備用的審計仍然可以使用。
根據(jù)設(shè)計,沙箱令牌不能保護下面這些不安全資源:
- 掛載的FAT或FAT32卷: 它們上面的安全描述符是有效空。在target中運行的惡意軟件可以讀寫這些磁盤空間,因為惡意軟件可以猜測或者推出出它們的路徑。
- TCP/IP: Windows 200和Windows XP(但在Vista中不會)中的TCP/IP socket的安全是有效空。使得惡意代碼與任何主機收發(fā)網(wǎng)絡(luò)包成為可能。
關(guān)于Windows 令牌對象的更多信息可以在底部參考文獻[02]查看。
作業(yè)對象
target進程也運行著一個作業(yè)對象。使用這個Windows機制,一些有趣的,不擁有傳統(tǒng)對象或者不關(guān)聯(lián)安全描述符的全局限制可以被強制執(zhí)行:
- 禁止用SystemParametersInfo()做用戶共享的系統(tǒng)范圍的修改,這可以用于切換鼠標(biāo)按鈕或者設(shè)置屏幕保護程序超時
- 禁止創(chuàng)建或修改桌面對象
- 禁止修改用戶共享的顯示設(shè)置,比如分辨率和主顯示器
- 禁止讀寫剪貼板
- 禁止設(shè)置全局Windows hook(使用SetWindowsHookEx())
- 禁止訪問全局原子表
- 禁止訪問在作業(yè)對象外創(chuàng)建的USER句柄
- 單活躍的進程限制(不允許創(chuàng)建子進程)
Chromium渲染器在激活所有這些限制的情況下允許。每個渲染器運行在自己的作業(yè)對象里。使用作業(yè)對象,沙箱可以(但當(dāng)前還不行)避免:
- 過度使用CPU周期
- 過度使用內(nèi)存
- 過度使用IO
有關(guān)Windows作業(yè)對象的詳細(xì)信息可以在底部參考文獻[1]中找到。
額外的桌面對象
令牌和作業(yè)對象定義來一個安全邊界:即,所有的進程有著相同的令牌,同一個作業(yè)對象中所有進程也處于同樣的安全上下文。然而。一個難以理解的事實是相同桌面上都有窗口上的應(yīng)用程序也處于相同的安全上下文中,因為收發(fā)window消息是不受任何安全檢查。通過桌面對象發(fā)送消息是不允許的。這是臭名昭著的“shatter”攻擊的來源,也是服務(wù)不應(yīng)該在交互桌面上托管窗口的原因。Windows桌面是一個常規(guī)的內(nèi)核對象,它可以被創(chuàng)建然后分配一個安全描述符。
在標(biāo)準(zhǔn)Windows安裝中,至少兩個桌面會與交互窗口站相關(guān)聯(lián),一個是常規(guī)(默認(rèn))桌面,另一個是登錄桌面。沙箱創(chuàng)建了第三個與所有target進程關(guān)聯(lián)的桌面。這個桌面永遠不可見,也不可交互,它有效地隔離了沙箱化進程,使其不能窺探用戶的交互,不能在更多特權(quán)的環(huán)境下發(fā)送消息到Windows。
額外的桌面對象唯一的優(yōu)點是它從一個隔離的池使用接近4MB的內(nèi)存,在Vista里可能更多。
信用等級
信用等級在Windows Vista及其之后的版本可用。它們不會用嚴(yán)格的方式定義安全的邊界,但他們確實提供了一種強制訪問控制(MAC),并且作為微軟IE沙箱的基礎(chǔ)而存在。
信用等級由一個特殊的SID和ACL對的集合實現(xiàn),它們代表了五種遞增等級:不受信任的,低級的,中級的,高級的,系統(tǒng)的。如果一個對象處于比請求令牌更高級的信用等級,訪問它就會受限。信用等級也實現(xiàn)了用戶界面權(quán)限隔離,這種隔離應(yīng)用了信用等級規(guī)則,讓同一個桌面中的不同進程可用交換窗口消息。
默認(rèn)情況下,令牌可以讀高信用等級的對象,但不能寫。大多數(shù)桌面應(yīng)用運行在中信用等級(MI),而較不受信任的進程像IE保護模式和我們自己的沙箱運行在低信用等級(LI)。一個低信用等級模式的令牌只可以訪問下面這些共享資源:
- 對大部分文件可以做讀訪問
- 對%USER PROFILE%、AppData、LocalLow目錄的寫訪問
- 讀注冊表的大部分內(nèi)容
- 對HKEY_CURRENT_USER\Software\AppDataLow目錄做寫訪問
- 剪貼板(為某些格式做復(fù)制粘貼)
- 遠程過程調(diào)用(RPC)
- TCP/IP Socket
- 通過ChangeWindowMessageFilter暴露窗口消息
- 通過LI標(biāo)簽共享內(nèi)存
- 擁有LI啟動激活的權(quán)限,訪問COM接口
- 通過LI標(biāo)簽暴露的命名管道
你會注意到之前描述的令牌屬性,工作對象,額外的桌面限制性更大,并且事實上會阻礙對上面列出的所有東西的訪問。所以,信用等級比其他措施更寬松,但這也可以被視為一種對深度防御的否定,并且,它的使用對性能或者資源使用不會有明顯的影響。
更多關(guān)于信用等級的信息可以在底部參考文獻[03]找到。
進程輕量化策略
大多數(shù)進程輕量化策略可以可以通過SetProcessMitigationPolicy方法應(yīng)用于Mtarget進程。沙箱使用這個API為target進程設(shè)置不同的各種策略,以強化安全特性。
重定位圖像:
- >= Win8
- 在進程中對所有圖片做隨機地址加載(ASLR)(必須被所有圖片支持)
堆之終結(jié):
- >= Win8
- 結(jié)束Windows堆占用進程
自底向上ASLR:
- >= Win8
- 設(shè)置隨機的下界作為進程的最小用戶地址
高熵值A(chǔ)SLR:
- >= Win8
- 為自底向上ASLR增加隨機等級到1TB。
嚴(yán)格句柄檢查:
- >= Win8
- 對于惡意句柄引用立即拋出異常
Win32k.sys鎖定:
- >= Win8
- ProcessSystemCallDisablePolicy,允許選擇性關(guān)閉target進程可用的系統(tǒng)調(diào)用
- 渲染器進程現(xiàn)在把這個功能設(shè)置到了DisallowWin32kSystemCalls上,這意味著win32k.sys用戶模式的調(diào)用不再被允許。這極大地減少了來自渲染器的可用的內(nèi)核攻擊。查看這里獲取更多細(xì)節(jié)。
App容器(Low Box Token):
>= Win8
在Windows里,這由內(nèi)核層的一個Low Box Token實現(xiàn),它是有著限制優(yōu)先權(quán)(通常只有SeChangeNotifyPrivilege和 SeIncreaseWorkingSetPrivilege)的一個剝離版本,運行在低信用等級,這個容器還由一組“能力”實現(xiàn),它們可以映射到進程允許/拒絕做的事情(查看MSDN獲取更詳細(xì)的描述)。從沙箱角度看,最有趣的能力是否決是對網(wǎng)絡(luò)的訪問,如果令牌是Low Box Token,INTERNET_CLIENT能力沒有出現(xiàn)的話,就會執(zhí)行網(wǎng)絡(luò)檢查。
因此沙箱對已有的限制令牌,添加了Low Box相關(guān)的屬性,并且不授予任何能力,以獲得沒有來自沙箱化進程的網(wǎng)絡(luò)訪問這樣的額外的網(wǎng)絡(luò)保護。
禁用字體加載:
- >= Win10
- ProcessFontDisablePolicy
禁用遠程設(shè)備圖像加載:
- >= Win10 TH2
- ProcessImageLoadPolicy
- 例:網(wǎng)絡(luò)資源的UNC路徑
禁用“強制低信用等級”的圖像加載:
- >= Win10 TH2
- ProcessImageLoadPolicy
- 例:臨時Internet文件
禁用額外的子進程創(chuàng)建:
- >= Win10 TH2
- 如果作業(yè)等級<= JOB_LIMITED_USER,用UpdateProcThreadAttribute()設(shè)置PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY為PROCESS_CREATION_CHILD_PROCESS_RESTRICTED。
- 這是額外層面的防御,使得作業(yè)層可以從外部打破。[引用: ticket, Project Zero blog.]
其他警告
操作系統(tǒng)可能有一些bug。令人感興趣的是Windows API中允許跳過常規(guī)安全檢查的一些bug。如果存在這樣的bug,惡意軟件能夠穿透安全限制,broker策略,并且可能危害計算機。在Windows環(huán)境下,沒有實用的方式可以避免沙箱中的代碼調(diào)用系統(tǒng)服務(wù)。
另外,第三方軟件,尤其是反病毒解決方案,可能創(chuàng)建新的攻擊角度。最麻煩的是為了使用一些(通常是系統(tǒng)不愿其使用的)功能,注入動態(tài)鏈接庫的應(yīng)用程序。這些動態(tài)鏈接庫也會注入到沙箱進程中。在最好的情況下,他們會產(chǎn)生故障,在最糟的情況下,可能為其他進程或文件系統(tǒng)本身造出后門,讓精心設(shè)計的惡意軟件逃離沙箱。
沙箱策略
應(yīng)用與target進程的真實限制通過策略設(shè)置。這些策略只是一種broker調(diào)用的編程接口,它們定義了限制與權(quán)限。四個函數(shù)控制這種限制,對應(yīng)四種Windows機制:
- TargetPolicy::SetTokenLevel()
- TargetPolicy::SetJobLevel()
- TargetPolicy::SetIntegrityLevel()
- TargetPolicy::SetDesktop()
前三個調(diào)用接收從非常嚴(yán)格到非常寬松的整數(shù)等級參數(shù),例如令牌有七個等級,作業(yè)有五個等級。Chromium渲染器通常運行四種機制中最嚴(yán)格的模式。最后,桌面策略有兩種,只能用于表示一個target進程是否運行在額外的桌面對象中。
這些限制是粗糙設(shè)計的,因為它們會影響目標(biāo)可訪問的所有可保護資源,但有時我們需要更精細(xì)粒度的分辨能力。沙箱策略接口允許broker指定例外的情況。一個例外是,在target中發(fā)出特定Windows API調(diào)用,將其代理給broker的方式。broker可以檢查參數(shù),使用不同的參數(shù)重新發(fā)出調(diào)用,或者干脆拒絕調(diào)用。為了指定例外情況,需要有一個獨立的調(diào)用:AddRule。現(xiàn)在支持以下幾種針對不同的Windows子系統(tǒng)的規(guī)則:
*文件
*命名管道
*進程創(chuàng)建
*登記
*同步對象
每種子系統(tǒng)的具體形式各不相同,但通常規(guī)則會基于字符串模式得到觸發(fā)。例如,一種可能的文件規(guī)則是:
AddRule(SUBSYS_FILES, FILES_ALLOW_READONLY, L"c:\\temp\\app_log\\d*.dmp")
這個規(guī)則指定了當(dāng)一個target進程想要打開文件時,可以授予的權(quán)限,以及匹配字符串格式的文件的只讀權(quán)限;例如 c:\temp\app_log\domino.dmp是一個滿足上面那種格式的文件。查詢頭文件可以獲得最新支持的對象與行為的列表。
規(guī)則只能在每個進程產(chǎn)生前添加,當(dāng)target運行時不能修改,但不同的target可以有不同的規(guī)則。
Target引導(dǎo)
Target不會從策略定義的限制開始執(zhí)行。他們從與常規(guī)用戶進程擁有的令牌非常接近的一個令牌開始執(zhí)行。因為在進程引導(dǎo)的過程中,操作系統(tǒng)加載器會訪問大量的資源,其中大部分是未認(rèn)證且隨時會變化的。另外,大部分應(yīng)用程序使用標(biāo)準(zhǔn)開發(fā)工具提供的標(biāo)準(zhǔn)CRT,在進程得到引導(dǎo)后,CRT也需要初始化,這時CRT初始化的內(nèi)部再次變成未認(rèn)證狀態(tài)了。
因此,在引導(dǎo)階段,進程實際上使用了兩種令牌:鎖定令牌,也是進程令牌,還有初始令牌,被設(shè)置為初始線程的模擬令牌。事實上,真正的SetTokenLevel定義是:
SetTokenLevel(TokenLevel initial, TokenLevel lockdown)
在所有的初始化操作完成后,main()或WinMain()會繼續(xù)執(zhí)行,還有兩個令牌會存活,但只有初始線程可以使用更強大的那個初始令牌。target的責(zé)任是在準(zhǔn)備完成后銷毀初始令牌。通過下面這個簡單的調(diào)用實現(xiàn):
LowerToken()
在target聲明這個調(diào)用之后,唯一可用的令牌是鎖定令牌,完整的沙箱限制開始生效。這個調(diào)用不可以撤銷。注意初始令牌是一個模擬令牌,它只對主線程有效,target進程創(chuàng)建的其他線程只使用鎖定令牌,因此不會嘗試獲取任何需要安全檢查的系統(tǒng)資源。
target始于特權(quán)令牌的事實簡化了顯式策略,因為任何特權(quán)相關(guān)的需要在進程啟動時一次完成的東西,可用在LowerToken()調(diào)用前完成,并且不需要在策略中設(shè)置規(guī)則。
重要
請確保初始令牌獲取的任何敏感操作系統(tǒng)句柄在調(diào)用LowerToken()前關(guān)閉。任何泄露的句柄可能被惡意軟件利用以逃離沙箱。
參考文獻
[01] Richter, Jeffrey "Make Your Windows 2000 Processes Play Nice Together With Job Kernel Objects"
http://www.microsoft.com/msj/0399/jobkernelobj/jobkernelobj.aspx
[02] Brown, Keith "What Is a Token" (wiki)
http://alt.pluralsight.com/wiki/default.aspx/Keith.GuideBook/WhatIsA令牌.htm
[03] Windows Integrity Mechanism Design (MSDN)