安全機制

安全機制包括兩個不同的部分,第一是網頁的安全,包括但是不限於網頁資料安全傳輸、跨域訪問、使用者資料安全等,第二部分是遊覽器的安全,具體是指網頁或者JavaScript程式碼有一些安全問題或者存在安全漏洞,遊覽器也能夠在執行它們的時候保證自身的安全,不受攻擊從而洩漏資料或者使系統破壞

網頁安全模型

安全模型基礎

當使用者訪問網頁的時候,遊覽器需要確保該網頁中資料的安全性,如Cookie、使用者名稱和密碼等資訊不會被其他的惡意網頁所獲取。

它表示的是網頁所在的域名、傳輸協議和埠等資訊,域是表明網頁身份的重要標識,如網頁“http://blog.csdn.net/steward2011”,它的域是”http://blog.csdn.net“,其中”http:”是協議,”blog.csdn.net”是域名,而埠預設為80,使用者可以開啟chrome遊覽器的開發者工具和控制檯,輸入”window.location”檢視域的各種資訊。根據安全模型的定義,不同域中網頁間的資源訪問是收到嚴格限制的,也就是網頁的DOM物件、個人資料、XMLHttpRequest等需要收到控制,預設情況下,不同網頁間的這些資料是被遊覽器隔離的,不能互相訪問,這是HTML的“Same origin Policy”策略。

XSS

XSS全稱Cross Site Scripting,其含義是執行跨域的JavaScript指令碼程式碼,執行指令碼本身沒什麼問題,但由於執行其他域的指令碼程式碼可能存在嚴重的危害,還有可能會盜取當前域中的各種資料,因此HTML5規範之前,跨域的資源共享是不被允許的,這樣做會造成功能上的缺陷,為此標準組織和WebKit使用了大量的技術來避免各種攻擊的發生,例如在HTTP訊息頭中定義了一個名為“X-XSS_Protection”的欄位,此時遊覽器會開啟防止XSS攻擊的過濾器,目前主要的遊覽器都支援該技術。

CSP

Content Security Policy是一種防止XSS攻擊的技術,它使用HTTP訊息頭來指定網站能夠標註哪些域中的哪些型別的資源被允許載入在該域的網頁中,包括JavaScript、CSS、HTML Frames、字型、圖片和嵌入物件(如外掛、Java Applet等),在HTTP訊息頭中,可以使用相應的欄位來控制這些域和資源的訪問,其主要是伺服器返回的HTTP訊息頭,目前不同遊覽器中使用不同的欄位名來表示,主要包含三種名稱:Content-Security-Policy(由標準組織定義)、X-WebKit-CSP(實驗性的欄位名)和X-Content-Security-Policy(Firefox使用),該欄位的定義格式如下(欄位名:指令名 指令值;指令名 指令值;….. )。下表是包含一個欄位名及一系列的“指令名 指令值”對的列表,其包括11種型別的指令來控制網頁中的各種資源和安全行為:

指令名含義
default-src控制所有的資源,如果已經包含該指定資源的指令,那麼default-src優先順序較低,如果沒有包含該知道的指令,那麼使用default-src指令定義的內容
script-src用於控制JavaScript程式碼
stype-src用於控制CSS樣式表
img-src用於控制圖片資源
connect-src用於控制XMLHttpRequest、WebSocket等同連線相關
font-src用於控制字型資源
object-src用於控制“embed”、“object”、“applet”等元素載入的資源
media-src用於控制多媒體資源,包括音訊和視訊
frame-src用於控制可以載入的框
sandbox用於控制網頁中是否允許彈出對話方塊,外掛和指令碼的執行等,值可能是”allow-forms”、”allow-same-origin”、”allow-script”、”allow-to-navigation”
report-uri將錯誤訊息傳送到指定的URI
CORS

根據“Same Origin Policy”原則,遊覽器做了很多的限制以組織跨域的訪問,所以跨域的資源共享又變成了一個問題,標準組織為了適應現實的需要,zhi’ding 額CORS(Cross Origin Resource Sharing)規範,也就是跨域資源共享,該規範藉助域HTTP訊息頭並通過定義一些欄位來實現,主要是定義不同域之間互動資料的方式,當某個網頁希望訪問其他域資源的時候,需要按照CORS定義的標準從一個域訪問另外一個域的資料。CORS使用HTTP頭來描述規範定義的內容,HTTP訊息頭是指包含有限個欄位(如Accept、Accept-language等)並請求型別只是HEAD、GET和POST。通常簡單的HTTP訊息頭只需要較小的代價,而包含了CORS的訊息頭卻不是簡單的HTTP訊息頭,該訊息請求在CORS裡面被稱為“Preflight”訊息請求,CORS使用到的欄位如下表:

欄位名型別含義
Origin請求端請求端申明該請求來源於哪個域
Access-Control-Request-Method請求端請求端的HTTP請求型別,如PUT、GET、HEAD等
Access-Control-Request-Headers請求端一個以“,”為分隔符的列表,表項是自定義請求的欄位
Access-Control-Allow-Origin響應端表明響應端允許的域,可以指定特定的域,也可以使用“*”表示允許所有的域請求
Access-Control-Allow-Credentials響應端預設情況Cookie之類的資訊是不能共享的,但如果設定該欄位為真,那麼Cookit是可以傳輸給請求端的
Access-Control-Expose-Headers響應端是否暴露回覆訊息給XHR,以便XHR能夠讀取響應訊息的內容
Access-Control-Max-Age響應端Prelight請求的有效時間
Access-Control-Allow-Methods響應端響應端 允許的HTTP請求型別,如前面的PUT、GET、HEAD等
Access-Control-Allow-Headers響應端響應端支援的自定義欄位

其型別可以分成請求段和相應端,如果每個HTTP訊息頭都要包含這些欄位那是一種浪費,因為沒有必要每個HTTP訊息頭都重複包含這些型別,為了就會使用到“Preflight”請求來傳送包含CORS欄位的訊息,而其他則是簡單的HTTP訊息頭,表中Access-Control-Max-Age表示Prefight請求的有效期,在有效期內不需要重複傳送CORS定義欄位的訊息,CORS和CSP的區別在於CSP定義的是網頁自身能夠訪問的某些域和資源,而CORS定義的是一個網頁如何才能訪問被同源策略禁止的跨域資源,規定了兩者互動的協議和方式。

Cross Document Messaging

Cross Document Messaging定義的是通過window.postMessage介面讓JavaScript在不同域的文件中傳遞訊息成為可能,以下程式碼演示瞭如何使用該技術來傳遞訊息:

http://csdn.com中JavaScript程式碼
contentWin.postMessage('Hello','http://blog.csdn.net');
http://blog.csdn.net/steward網頁中的JavaScript程式碼
window.addEventListener('message',function receiver(e)) {
if (e.origin == 'http://myweb.com') {
if (e.data == 'Hello') {
e.source.postMessage('Hello2', e.origin);
} else {
alert(e.data);
}
}
}, false);

該機制使用“window”物件的postMessage方法來傳遞給其他域網頁訊息,該方法包含兩個引數,第一個是訊息內容,第二個是需要對方的域訊息,而在接收方,開發者在JavaScript程式碼中註冊一個訊息響應函式,如果檢測出訊息來源於上述“http://csdn.com”,那麼就回復一個“Hello2”的訊息。

安全傳輸協議

對於使用者而言,網頁的安全還包含一個重要點,就是使用者和伺服器之間互動資料的安全性問題,對於一般的網頁而言,這些資料的傳輸都是使用明文方式,也就是說它們對誰都是可見的,這能夠滿足大多數的使用情況,但是對於隱私的資料,如密碼、銀行帳號等,如果使用明文來傳輸就存在風險,為此Web引入了安全的資料傳輸協議HTTPS,HTTPS是在HTTP協議之上使用SSL(Secure Socket Layer)技術來對傳輸的資料進行加密,從而保證了資料的安全性,SSL協議是構建在TCP協議之上、應用層協議HTTP之下的,SSL工作的主要流程是先進行伺服器認證,然後是使用者認證,SSL協議主要是服務提供商對使用者資訊保密的承諾,這有利於提供商而不利於消費者,同時SSL還存在一些問題,例如只能提供交易中客戶域伺服器間的雙方認證,在涉及多方的電子交易中,SSL協議並不能協調各方的安全傳輸和信任關係。TLS(Transport Layer Security)是在SSL3.0基礎上發展起來的,它使用了新的加密演算法,因此同HTTPS之間不相容,TLS用於兩個通訊應用程式之間,提供保密性和資料完整性,該協議是由兩層子協議組成的,包括TLS記錄協議(TLS Record)和TLS握手協議(TLS Handshake),較低的層為TLS記錄協議,位於TCP協議之上,TLS握手協議具有三個屬性,其一是可以使用非對稱的密碼術來認證對等方的身份,其二是共享加密金鑰的協商是安全的,對偷竊者來說協商加密是難以獲得的,此外經過認證的連線不能獲取加密,即使是進入連線中間的攻擊者也不能,其三是協商是可靠的,如果沒有經過通訊方成員的檢測,任何攻擊者都不能修改通訊協商。TLS獨立於高層協議,如HTTP協議,高層協議如HTTP協議可以透明的分佈在TLS協議上面,然而,TLS標準並沒有規定應用程式如何在TLS上增加安全性,它把如何啟動TLS握手協議及如何解釋交換的認證證書的決定權留給協議的設計者和實施者來判斷。

WebKit的實現

首先看WebKit為了防止XSS攻擊所做的工作,下圖是WebKit中啟動XSS過濾功能所使用的相關基礎設施,為了防止XSS攻擊,需要在解釋HTML的過程中進行XSS過濾,也就是對詞法分析器分析之後的詞語(Token)進行過濾,以發現潛在的問題:
這裡寫圖片描述
基本工作是這樣,在HTMLDocumentParser類揭示出一個詞語之後,如果需要進行XSS過濾功能,則每一個詞語使用HTMLDocumentParser類的XSSAuditor物件來進行過濾,也就是圖中的XSSAudior::filterToken函式,對於每一個詞語,該函式進行過濾並生成相應的結果XSSInfo物件,該物件包含是否需要阻止整個頁面渲染等資訊,XSSAuditor不做決定,而是由HTMLDocumentParser將這些資訊交給XSSAuditorDelegate類來處理,在根據這些資訊來生成報告,XSSAuditorDelegate將結果報告傳送給“report-uri”,XSS有很多種攻擊的型別,這裡主要包括對於元素開始和結束及其屬性的檢查,同時對於一些特定型別的詞語進行過濾,包括input、form、button、iframe、script等,當發現潛在危險的時候再生成相應的結果資訊此處為XSSInfo物件。其次是CSP方面的支援,下圖是WebKit支援CSP所定義的相關基礎設施,同時包括Origin的定義,其中對於CSP支援的主要部分是ContentSecurityPolicy和SecurityContext這兩個類:
這裡寫圖片描述

  • ContentSecurityPolicy:主要包括對於規範中定義的各個欄位的解釋和解釋後內容的儲存,如圖中的didReceiveHeader函式就是處理伺服器端的HTTP訊息頭,該類將指令和指令的內容儲存在”m_policies”中,形成一個列表
  • SecurityContext:支援安全機制的上下文類,包含Origin物件和ContentSecurityPolicy物件,其他對CSP等的呼叫都是通過該類來獲取的

圖中最下部分為兩個類WebSecurityOrigin和WebSecurityPolicy,這是WebKit的Chromium移植定義的兩個介面,可以被Chromium呼叫,它們都有內部的實現,具體分別是SecurityOrigin和SecurityPolicy,SecurityOrigin就是規範中對於Origin的定義,而SecurityPolicy就是對CSP策略的定義,通過WebSecurityPolicy介面,Chromium可以自定義一些策略並設定到WebKit中。Document類間接繼承了SecurityContext,由此Document也繼承了CSP的設定,因為Document會在各處都使用,這樣方便呼叫CSP的功能,DOMSecurityPolicy為了將CSP的資訊暴露到JavaScript中,這樣JavaScript程式碼可以獲取CSP定義的內容,如“script-src”指令所定義的允許訪問的域,ResourceFetcher是獲取資源的類,根據CSP的定義,對於各種型別的資源,在獲取之間都需要檢查該資源是否在CSP定義的允許範圍內,如果不在,則拒絕請求,並報告錯誤,如果在,則發起請求,該請求需要依賴SecurityPolicy提供的一些資訊。最後是CORS的支援,下圖是WebKit支援CORS所涉及的一些類,其中最主要的是CrossOriginAccesControl部分,它不是一個類,裡面只是包含了一組全域性函式,用來幫助生成符合CORS規範的“Preflight”請求或者其他簡單請求,同時包括處理來自回覆端的訊息,在WebKit使用WebURLLoader請求的時候,使用這些方法能夠生成相應的請求:
這裡寫圖片描述

沙箱模型

原理

一般而言,對於網路上的網頁中的JavaScript程式碼和外掛是不受信的,特別是一些故意設計侵入遊覽器執行的主機程式碼更是危險,通過一些手段或者遊覽器中的漏洞,這些程式碼可能獲取了主機的管理許可權,這對主機系統來說十分危險,所以除了保證網頁本身之外,還需要保證遊覽器和遊覽器所在的系統不存在危險。對於網路上的網頁,遊覽器認為它們是不安全的,因為網頁總是存在各種可能性,也許是無意或有意的攻擊,如果有一種機制,將網頁的執行限制在一個特定的環境中,也就是一個沙箱中,使它只能訪問有限的功能,那麼即使網頁工作的渲染引擎被攻擊,它也不能夠獲取渲染引擎工作的主機系統中的任何許可權,這就是沙箱模型的思想。Chromium是以多程序為基礎的,網頁的渲染在一個獨立的Renderer程序中,這位實現沙箱模型提供了基礎,因為可以相對容易的使用一些技術將整個網頁的渲染過程放在一個受限的程序中來完成,如下圖所示,受限的環境只能被某些或者很少的系統呼叫而且不能直接訪問使用者資料,沙箱模型工作的基本單位就是程序。
這裡寫圖片描述
Chromium的沙箱模型是利用系統提供的安全技術,讓網頁在執行過程中不會修改作業系統或者是訪問系統中的隱私資料,而需要訪問系統資源或者說是系統呼叫的時候,通過一個代理機制來完成。

實現機制

由於沙箱模型依賴作業系統提供的技術,而不同作業系統提供的安全技術是不一樣的,這意味著不同作業系統上的實現是不一致的,需要分別針對不同平臺來討論,但是不管是Linux還是Windows,或者是其他平臺,Chromium都是在程序的力度下來實現沙箱模型,也就是說需要執行在沙箱下的操作都是一個單獨的程序:
這裡寫圖片描述
圖中右側是目標程序,也就是需要在沙箱中執行的程式碼,左側是代理程序,它需要負責建立目標程序併為目標程序設定各種安全策略,同時建立IPC連線,接受目標程序的各種請求,因為目標程序是不能訪問過多資源的。

Linux

在Linux上,沙箱模型分成兩個層,第一層是阻止某個或者某些程序通常能夠訪問的資源,chromium中稱為“語義層,這裡使用的系統技術主要是“setuid“,第二層是防止程序訪問能夠攻擊核心的介面或者供給面,這裡使用的系統技術主要是”Seccomp”,在沙箱機制啟動之後,如果執行Chromium程式,會產生下面的程序層次結構,它是一棵樹,樹的根節點是“browser“程序,該程序啟動後,會孵化多個子程序,包括”GPU“、”chrome_sandbox“等程序,而對於沙箱模型來說,這裡關注”chrome_sandbox“程序,它的目的主要是使用”setuid“技術來實現模型的第一層,生成了”zygote“子程序,其中”chrome_sandbox“程序使用的是上面介紹的目標”chrome_sanbox”生成的二進位制可執行檔案,而其它的是目標”chrome“生成的結果,二者是不一樣的。
這裡寫圖片描述
生成第一個”zygote“之後,該程序會生成兩個子程序,第一個是”nacl-helper“程序,是為了支援NaCl外掛程序服務的,第二個又是一個”zygote“,這個不同於它的父親,主要是為了生成各種”Renderer“程序服務,這樣每個”Renderer“程序經過上面的過程後都會使用沙箱機制進行處理,網頁在”Renderer“中的執行就收到了限制,Renderer程序域代理程序通過程序間通訊機制來互動,所有的請求都是傳送給代理程序,代理程序將結果返回給Renderer程序,這裡的代理程序就是Browser程序,Browser程序擁有訪問這些資源和系統呼叫的許可權。其中第一層主要使用兩種技術:

  • 使用setuid來為新程序設定新使用者ID和組ID,根據Linux的規定,兩個不同使用者ID之間的資料是隔離開的,這將Renderer程序同Browser程序分開,後者擁有訪問很多關鍵資料的能力,如各個網頁的Cookie,在現在的Chromium實現中,不再使用setuid來實現,而是使用CLONE_NEWPID標記,該標記是在Linux系統呼叫clone時設定,從而為新程序建立一個新的名空間,也就是上面描述的檔案系統等
  • 顯示網路訪問,Chromium使用標記”CLONE_NEWNET“設定在呼叫”clone“系統呼叫的引數中,使用這這些技術之後克隆出來的程序就同父程序分離開來,包括新檔案系統等和限制網路的訪問等

第二層使用的主要技術是Seccomp和Seccomp-BPF,seccomp是Linux核心提供的一種簡單的沙箱機制,它能夠允許程序進入一種不可逆的安全狀態,進入該狀態的程序只能夠呼叫4個系統呼叫,包括exit、sigreturn、read和write,而且最後兩個系統呼叫只能操作已經開啟的檔案描述符,如果該程序嘗試呼叫其他的系統呼叫,那麼核心會通過SIGKILL訊號來殺死該程序,進入該按去哪狀態的方法就是使用系統呼叫prctl社會自標記位PR_SET_SECCOMP就可以了,前提是系統的核心在編譯的時候就加入了對Seccomp的支援,因為不是所有使用Linux核心的作業系統都能開啟該機制,Seccomp-BPF是Seccomp及時的一個擴充套件,它允許使用BPF所定義的方法來將系統呼叫轉變成BPF格式的小程式,BPF(Berkeley Packet Filter)原是Berkeley開發的一種用來過濾網路包的技術,現在被應用在Seccomp,Seccomp-BPF將系統呼叫轉變成BPF格式的小程式,這些小程式能夠被核心所解釋,這樣每個系統呼叫的次數和引數都能夠被重新評估或者被限制。對於開發者來說,如果想要關閉第二層的沙箱技術只需在命令列韓總加入引數”–disable-seccomp-filter-sandbox“就可以了,對於Android系統來講,雖然Android是基於Linux核心開發出來的,但還是有些區別,目前沙箱機制的第二層在Android上並沒有得到支援,只是第一層得到了支援,但是在Android上,系統支援的安全機制都已經在Chrome的Android版本上得到了啟動,主要體現在兩個方面,第一是SUID,Android系統上稍微不同,它是UID isolation(UID隔離技術),Android可以為每一個程序設定一個新的UID,這些每個程序之間就不能隨意修改和訪問資料,這是由Linux核心機制來保證的。