王龑 — MAY 27, 2015
原文鏈接 The Spy in the Sandbox – Practical Cache Attacks in Javascriptjavascript
相關論文可在 https://github.com/wyvernnot/cache_attack_in_javascript 下載java
做者和單位ios
- Yossef Oren (yos AT cs.columbia.edu)
- Vasileios P. Kemerlis (vpk AT cs.columbia.edu)
- Simha Sethumadhavan (simha AT cs.columbia.edu)
- Angelos D. Keromytis (angelos AT cs.columbia.edu)
哥倫比亞大學計算機系git
咱們將展現首個徹底運行在瀏覽器裏的針對微架構的邊信道攻擊手段。與這個領域裏的其它研究成果不一樣,這一手段不須要攻擊者在受害者的電腦上安裝任何的 應用程序來展開攻擊,受害者只須要打開一個由攻擊者控制的惡意網頁。這種攻擊模型可伸縮性高,易行,貼近當今的網絡環境,特別是因爲絕大多數桌面瀏覽器鏈接到 Internet 所以幾乎沒法防護。這種攻擊手段基於 Yarom 等人在 文[23] 提出的 LLC攻擊
,可讓攻擊者遠程得到屬於其它進程、用戶甚至是虛擬機的信息, 只要它們和受害者的瀏覽器運行在運行在同一臺物理主機上。咱們將闡述這種攻擊背後的基本原理,而後用一種高帶寬的隱藏通道驗證它的效果,最後 用它打造了一個覆蓋整個系統的鼠標和網絡活動記錄器。抵禦這種攻擊是可能的,可是所需的反制措施對瀏覽器和電腦的正常使用所產生的代價有點不實際。github
邊信道分析是裏一種很是強大的密碼分析攻擊。攻擊者經過分析安全設備內部在進行安全運算時所產生的的物理信號(功率,輻射,熱量等)來取得祕密信息[15]。 聽說在二戰中便有情報部門在使用,Kocher 等人在1996年首次在學術情境下討論了這個問題[14]。邊信道分析被證明能夠用來侵入無數的現實世界中的系統,從汽車報警器 到高安全性的密碼協處理器[8][18]。緩存攻擊(Cache Attack)是和我的電腦相關的一種邊信道攻擊,由於高速緩衝區被不一樣的進程和用戶使用而致使了信息的泄露[17][11]。web
雖然邊信道攻擊的能力不容置疑,可是要實際應用到系統上仍是相對受限的。影響邊信道攻擊可行性的一個主要因素是對不肯定的攻擊模型的假設:除了基於網絡的 時序攻擊,大部分的邊信道攻擊都要求攻擊者很是接近受害者。緩存攻擊通常會假設攻擊者可以在受害者的機器上執行任意的二進制的代碼。雖然這個假設 適用於像 Amazon 雲計算平臺這樣的 IaaS 或者 PaaS 環境,可是對於其它環境就不那麼貼切了。算法
在這篇報告裏,咱們用一種約束更少、更可行的攻擊者模型挑戰了這一限制性的安全假設。在咱們的攻擊模型裏,受害者只須要訪問一個網頁,這個網頁 由攻擊者所擁有。咱們會展現,即便在這麼簡單的攻擊者模型裏,攻擊者依然可以在可行的時間週期裏,從被攻擊的系統中提取出有意義的信息。爲了和這樣的 計算設定保持一致,咱們把注意力集中在了跟蹤用戶行爲而不是獲取密匙上。報告中的攻擊方式所以是高度可行的:對於攻擊者的假設和限定是 實際的;運行的時間是實際的;給攻擊者帶來的好處也是實際的。據咱們瞭解,這是首個能夠輕鬆擴展至上百萬個目標的邊信道攻擊方式。小程序
咱們假設攻擊中受害者使用的我的電腦配備有較新型號的的 Intel CPU ,並進一步假設用戶用支持 HTML5 的瀏覽器訪問網頁。這覆蓋了絕大部分鏈接到 Internet 的 我的電腦,見 章節5.1 。用戶被強迫訪問一個頁面,這個頁面上有一個由攻擊者控制的元素好比廣告。攻擊代碼本身會執行基於 JavaScript 的 緩存攻擊,見 章節2,持續地訪問被攻擊系統的 LLC 。由於全部的 CPU 內核,用戶,進程,保護環等共享同一個高速緩存區,因此可爲攻擊者提供被攻擊用戶和系統的詳細信息。數組
現代的計算機系統一般會採用一個高速的中央處理器(CPU)和一個容量大可是速度較慢的隨機存取器(RAM)。爲了克服這兩個模塊的性能鴻溝,現代的計算機系統會採用 高速緩存 - 一種容量小可是速度更快的內存結構,裏面保存了 RAM
中最近被 CPU
訪問過的子集。高速緩存一般會採用** 分層** 設計,即在CPU
和 RAM
之間 分層 放置一些列逐漸變大和變慢的內存結構。圖1 取自 文[22],展現了 Intel Ivy Bridge 的緩存結構,包括:較小的 level 1(L1) cache,大一些的** level 2 (L2) cache ,最下方是最大的 level 3 (L3) cache** 並和 RAM 相連。Intel 目前代號爲 Haswell 的新一代 CPU 採用了另外一種嵌入式的 DRAM(eDRAM) 設計,因此不在本文討論範圍內。若是 CPU 須要訪問的數據當前不在緩存裏,會觸發一個 未命中 ,當前緩存裏的一項必須被 淘汰 來給新元素騰出空間。瀏覽器
圖1:Intel Ivy Bridge
Intel 的緩存微架構是 嵌套的 - 全部一級緩存裏的數據必須同時存在二級和三級緩存裏。倒過來,若是某個元素在三級緩存裏被淘汰,那它也會馬上被 從二級和一級緩存裏移走。須要注意的是 AMD 緩存微架構的設計是非嵌套的,因此本文描述的方法並不能馬上應用到該平臺上。
本文重點關注第三級緩存,一般也被稱爲 LLC。因爲 LLC 較大,CPU 訪問內存的時候若是把整個 LLC 的內容都搜索一遍效率會很低。 爲了不這個問題,LLC 一般被分紅不一樣的 組,每一組都對應者內存空間的一個固定的子集。每一個組包含若干緩存線。例如,Intel Haswell 系列中的 Core i7-3720QM 處理器擁有 8192 = 2^13 個組,每一個組有 12 條 64 = 2^6 字節的緩存線,共同組成 8192 x 12 x 64 = 6 MB 的高速緩存。 CPU 若是要檢查一個給定的物理地址是否在三級緩存裏,會先計算出組,而後只檢查組內的緩存線。結果就是,某個物理地址的緩存未命中,會致使同一個組的 爲數很少的緩存線中的一條被淘汰,這個事實會被咱們的攻擊反覆運用。由64比特長度的物理地址到13比特長度的組索引的映射方法已經被 Hund 等人在2013年 經過逆向工程得出來[12]。在表示物理地址的64個比特位裏,5到0被忽略,16到6被直接用來做爲組索引的低11位,63到17散列後獲得組索引的高2位。 LLC 被全部的內核、線程、進程、用戶,乃至運行在同一塊 CPU 芯片上的虛擬機所共享,而不論特權環或其它相似的保護措施。
現代的我的電腦採用了一種 虛擬內存機制,在這種機制裏,用戶進程通常沒法直接獲得或訪問系統的物理內存。取而代之的是,進程會被分配不一樣的虛擬內存頁。 若是某個虛擬內存頁被當前執行的進程訪問,操做系統會在物理內存裏動態地分配一個頁框。CPU 的內存管理單元(MMU)負責把不一樣進程對虛擬內存地址的訪問 映射到物理內存。Intel 處理器的頁和頁框大小通常是4KB,而且頁和頁框的是按照頁對齊的 - 每頁的開始地址是頁大小的倍數。這意味着,任何虛擬地址 的低12位和對應的虛擬地址是一一對應的,這一事實也在咱們的攻擊中用到。
緩存攻擊是針對微架構的攻擊手段中一個典型的表明, Aciamez 在他的出色的調查中將這類攻擊定義爲利用 「信任架構邊界下方的底層處理器結構」 從不一樣的安全系統中 獲取祕密信息。緩存攻擊基於這樣的事實:儘管在上層有諸多像沙箱、虛擬內存、特權環,宿主這樣的保障機制,安全和不安全進程經過高速緩存區的共用能夠互相影響。 攻擊者構造一個「間諜」進程後能夠經過被共用的緩存來測量和干擾其它安全進程的內部狀態。Hu 在1992年的首次發現[11],在隨後的一些研究成果裏顯示了邊信道攻擊可被用來獲取 AES密匙[17][4],RSA密匙[19],甚至能夠容許一臺虛擬機侵入宿主上的其它機器。
咱們的攻擊創建在 填充+探測 模型的基礎上,這個方法由 Osvik 在[17]中首次描述,不過是針對一級緩存的。以後由 Yarom 等人在[23]中擴展到啓用了 較大內存頁系統的 LLC。咱們把這個方法擴展了一下支持更加常見的 4K 的頁大小。總的來講,填充+探測有四個步驟。第一步,攻擊者創建一個 或多個** 移除集。移除集是內存中的一系列地址,這些地址被訪問的時候會佔據受害者進程使用的一條緩存線。第二步,攻擊者經過訪問移除集填充整個組。 這會強制受害者的代碼或指令被從組中淘汰,並使組進入一個已知的狀態。第三步,攻擊者觸發或只是等待受害者執行和可能使用組。最後,攻擊者經過再次訪問移除集來探測**組。若是訪問的延遲比較低,意味着攻擊者的指令或數據還在緩存裏。不然,較高的訪問延遲意味着受害者的代碼用到了組,所以攻擊者能夠了解受害者的內部狀態。 實際的時間測量是用非特權的彙編指令RDTSC進行的,這個指令能夠獲得處理器很是準確的週期數。再次遍歷鏈表還有第二個目的,那就是強制組進入 受攻擊者控制的狀態,爲下一輪的測量作好準備。
JavaScript 是一種擁有動態類型,基於對象的運行時求值的腳本語言,它支撐着現代互聯網的客戶端。JavaScript 代碼以源碼的形式傳到瀏覽器端,由瀏覽器 即時編譯(JIT) 機制來編譯和優化。不一樣瀏覽器廠商之間的激烈競爭使不斷改進 JavaScript 性能備受關注。結果就是,在某些場景下,JavaScript 執行的效率已經 能夠和機器語言相媲美。
JavaScript 語言的核心功能是由 ECMA 產業協會在 ECMA-262 標準中定義的。語言標準由萬維網協會(W3C)定義的一系 API 所補充,所以適合開發 Web 內容。 JavaScript API 的集合是不斷演進的,瀏覽器廠商依照本身的開發計劃不斷增長新的 API 支持。咱們的工做中用到兩個具體的API: 第一個是類型數組的定義9,經過它能夠高效地訪問非結構化的二進制數組。 第二個是高精度時間API16,讓應用程序能夠進行毫秒如下時間的測量。 如 章節5.1 所示,大部分當今主流的瀏覽器都同時支持這兩個API。
JavaScript 代碼運行在高度沙箱化的環境裏 - 用 JavaScript 交付的代碼對系統的訪問很是受限。例如,JavaScript 代碼若是沒有用戶的容許不能打開和讀取文件。 JavaScript 代碼不能執行機器語言或者加載本地的代碼庫。 最值得注意的是,JavaScript 代碼沒有指針的概念,因此你連一個 JavaScript 變量虛擬地址都無法知道。
咱們的目的是構造一個能夠經過 Web 部署的 LLC 攻擊。這個過程是充滿挑戰的,由於 JavaScript 代碼無法加載共享庫或者執行本機語言的程序, 而且因爲沒法直接調用專用的彙編指令而被迫調用腳本語言的函數進行時間的測量。儘管有這些挑戰,咱們仍是成功地把緩存攻擊擴展到了基於 Web 環境:
- 咱們展現了一種用來在 LLC 上的創建 非典型移除集 特別方法。與[23]不一樣,咱們的方法不要求系統配置成支持較大的內存頁,因此可以很快的 應用到普遍的桌面和服務器系統。咱們展現了該方法雖然是使用 JavaScript 實現的,可是依然能夠在實際的時間週期裏完成。
- 咱們展現了一種 功能完善的用無需特權的 JavaScript 發動 LLC 攻擊 的方法。咱們用隱藏通道的方式,評估了它的性能,包括在同一個機器、不一樣進程之間 和在虛擬機與它的主機之間。基於 JavaScript 的通道與[23]中用機器語言實現的方法相似,均可以達到每秒幾百 kb 的速度。
- 咱們展現了怎麼利用基於緩存的方法來有效地跟蹤用戶行爲。緩存攻擊的這一應用與咱們的攻擊模型更相關,這與密碼分析在其它成果中的應用不一樣。
- 最後,咱們分析了針對攻擊可能的反制措施和整個系統的代價。
文檔結構: 第二章,攻擊方法不一樣階段的設計與實現。 第三章,基於攻擊方法創建起來的隱藏通道,這個通道也被用來驗證方法的性能。 第四章,緩存攻擊如何被用來跟蹤用戶在瀏覽器內外的行爲。 第五章,總結,提出反制措施和仍未解決的研究挑戰。
正如前文所訴,一次成功的 填充+探測 攻擊包含幾個步驟:爲一個或多個相關組創建移除集,填充緩存,觸發受害者的操做,最後再次探測組。 雖然填充和探測實現起來很簡單,可是要找到對應於某個系統操做的組而且爲它創建移除集就不那麼容易了。在本章裏,咱們描述了這幾個步驟用 JavaScript 如何實現。
正如[23]寫到,填充+探測攻擊方法的第一步是爲某個與被攻擊進程共享的組創建一個移除集。這個移除集包含一系列的變量,並且這些變量都被 CPU 映射到相同的 組裏。根據 文[20] 的建議,使用鏈表能夠避免 CPU 的內存預讀和流水線優化。咱們首先展現如何爲任意一個組創建一個移除集,而後解決尋找與受害者共享組的問題。
文[17]指出,一級緩存是依據虛擬地址的低位的比特來決定組分配的。假設攻擊者知道變量的虛擬地址,那麼在基於一級緩存的攻擊模型裏創建移除集很容易。 可是,LLC 裏變量的組分配是依照物理內存的地址進行的,並且通常狀況下,非特權進程沒法知道。文[23]的做者爲了規避這個問題,假設系統用的是 頁較大的模型,在這個模型裏,物理地址和虛擬地址的低21位是相同的,並經過迭代算法來得到組索引的高位。
在咱們所考慮的攻擊模型裏,系統運行在 4K 的頁大小模型下,物理地址和虛擬地址只有最低的12位是相同的。然而更大的難題是,JavaScript沒有指針的概念, 因此即便是本身定義的變量,虛擬地址也是不知道的。
從64位物理地址到13位的組索引的映射關係已經被 Hund 等人研究過[12]。他們發現,當訪問物理內存裏一段連續的、8MB大小的 「淘汰緩衝區」 時會讓三級緩存裏的全部組 都失效。雖然咱們在用戶態下沒有辦法分配這樣的一個「淘汰緩衝區」 (實際上,文章[12]是經過內核模式的驅動實現的),咱們用 JavaScript 在 虛擬內存裏分配了一個 8MB 大小的數組(這實際上是由系統分配的隨機、不連續的 4K 大小物理內存頁的集合),而後測量遍歷這個緩衝區在全系統形成的影響。 咱們發如今迭代訪問了這個淘汰緩衝區後若是當即訪問內存中其它不相關的變量,訪問的延遲會顯著的增長。 另一個發現是,即便不訪問整個緩衝區而是每隔64字節去訪問它,這個現象依然存在。可是,咱們所訪問的 131K 個偏移值到8192個可能的組的映射關係 並無馬上清晰起來,由於咱們不知道緩衝區裏各個頁在物理內存中的地址。
解決這個問題一個不太靠譜的作法是,給定一個任意的「受害者」在內存中的地址,經過暴力手段從 131K 個偏移值中找到12個與這個地址共享組的地址。要完成這點, 咱們能夠從 131K 個偏移量中選取幾個做爲子集,在迭代了全部的偏移量後再測量下訪問的延遲有沒有變化。若是延遲增長了,意味着含有12個地址的子集與 受害者地址共享相同的組。若是延遲沒有變化,那子集裏的12個地址中的任何一個都不在組裏,這樣受害者地址就還在緩存裏。把這個過程重複8192遍,每次用 一個不一樣的受害者地址,咱們就能夠識別每一個組而且創建本身的數據結構。
受此啓發而馬上寫出來的程序會運行很是長的時間。幸運的是, Intel MMU 的頁幀大小(章節1.1)很是有幫助,由於虛擬地址是頁對齊的,每一個虛擬地址的 低12位和每一個物理地址的低12位是一致的。據 Hund 等人所稱,12個比特中的6個被用來惟一決定組索引。所以,淘汰緩衝區中的一個偏移會和其它 8K 個偏移 共享12到6位,而不是全部 131K 個。此外,只要找到一個組就能馬上知道其它的63個在相同頁幀裏的組的位置。再加上 JavaScript 分配大的數據緩存區的時是 和頁幀的邊界對齊的,因此能夠用算法1中的貪心算法。
算法1 Profiling a cache set Let S be the set of unmapped pages, and address x be an arbitrary page-aligned address in memory
1. Repeat k times: (a) Iteratively access all members of S (b) Measure t1 , the time it takes to access x (c) Select a random page s from S and remove it (d) Iteratively access all members of S\s (e) Measure t2 , the time it takes to access x (f) If removing page s caused the memory access to speed up considerably (i.e., t1 − t2 > thres), then this page is part of the same set as x. Place it back into S. (g) If removing page s did not cause memory access to speed up considerably, then this address is not part of the same set as x. 2. If |S| = 12, return S. Otherwise report failure.
經過屢次運行 算法1,咱們能夠逐漸的創建一個移除集並覆蓋大部分的緩存,除了那些被 JavaScript 運行時自己所使用的。咱們注意到, 與[23]中的算法創建的淘汰緩衝區不一樣,咱們的移除集是非典型的 - 由於 JavaScript 沒有指針的概念,因此若是咱們發現了一個移除集 咱們並無辦法知道它對應着 CPU 高速緩存的哪一個組。此外,在相同的機器上每次運行這個算法都會獲得不一樣的映射。這也許是由於用了傳統的 4K 頁大小 而不是 2MB 的頁大小的緣由,這個問題即便不用 JavaScript 用機器語言也存在。
咱們用 JavaScript 實現了 算法1 而且在安裝了 Ivy Bridge, Sandy Bridge,Haswell 系列 CPU 的機器上進行驗證,機器上裝有 Safari 和 Firefox 對應運行在 Mac OS Yosemite 和 Ubuntu 14.04 LTS 操做系統上。系統並無被配置使用大的頁而是用默認的 4K 頁大小。列表1 顯示了實現 算法1.d 和 算法1.e 的代碼,展現了 JavaScript 下怎麼遍歷鏈表和測量時間。算法若是要運行在 Chrome 和 Internet Explorer 下,須要額外的幾個步驟,在 章節5.1 中。
列表1
// Invalidate the cache set var currentEntry = startAddress; do { currentEntry = probeView.getUint32(currentEntry); } while (currentEntry != startAddress); // Measure access time var startTime = window.performance.now(); currentEntry = primeView.getUint32(variableToAccess); var endTime = window.performance.now();
圖2 性能分析算法的累積表現
圖2顯示了性能分析的結果,運行在 Intel i7-3720QM CPU 上, 裝有 Firefox 35.0.1 和 Mac OS 10.10.2 。咱們很高興地發如今30秒內就 映射了超過25%的組,1分鐘內就達到了50%。這個算法想要並行運行是很是簡單的,由於大部分的執行時間花在了數據結構的維護上,只有一小部分花在讓緩存失效和 測量上。整個算法用不到500行 JavaScript 代碼就能夠完成。
圖3 Haswell 上兩種方法訪問延遲的機率分佈
爲了驗證咱們的算法可以辨別不一樣的組,咱們設計了一個實驗來比較一個變量被 flush 先後的訪問延遲。圖3 顯示了兩種方式訪問變量的機率分佈函數。 灰色的表明用咱們的方式從緩存中 flush 出去的變量的訪問時間;而黑色是駐留在緩存裏的變量的訪問時間。時間的測量用到 JavaScript 的高精度計時器, 因此還包括了 JavaScript 運行時的延遲。二者的不一樣是顯而易見的。圖4 顯示的是在較早版本的 Sandy Bridge CPU 上捕捉到的結果,該型號每一個組有16個條目。
經過選取一些列的組,而且不斷的測量它們的訪問延遲,攻擊者能夠得到緩存實時活動很是詳細的圖。咱們把這種視覺呈現稱做 「內存譜圖」,由於它看起來很像聲音的譜圖。
圖4 Sandy Bridge 上兩種方法訪問延遲的機率分佈
圖5 內存譜圖示例
圖5顯示的是每隔400ms抓取一次的內存譜圖。其中X軸對應時間,Y軸對應不一樣的組。例子中的時間分辨率是250微秒,檢測了一共128個組。每一個點的密度 表明了這個組在這個時間的訪問延遲。黑色表明延遲較低,意味從上次測量到如今沒有其它進程訪問過這個組。白色意味着攻擊者的數據在上次測量以後被淘汰了。
細看這個內存譜圖能夠獲得幾個顯而易見的事實。首先,雖然沒用機器語言指令而是用了 JavaScript 的計時器,測量的抖動很小,活躍和不活躍的組 很容易被區分。圖中有幾條明顯的垂直的線,意味着同一時間間隔裏有多個相鄰的組被訪問。由於連續的組對應的物理內存的地址也是連續的,因此咱們 相信這個信號表明着一個超過 64 字節的彙編指令。還有一些聚在一塊兒的組被同時訪問。咱們推斷這表明着變量的訪問。最後,橫着的白線預示着一個變量 被不斷地訪問。這個變量多是屬於測量代碼的或屬於當前的 JavaScript 運行時。從一個沒有任何特權的網頁能獲得這麼多信息真是太了不得了。
移除集讓攻擊者可以監控任意一個組的活動。由於咱們獲得的移除集是非典型的,所以攻擊者必須想辦法把分析過的組和受害者的數據或是代碼的地址 關聯起來。這個學習/分類的問題已經由 Zhang 和 Yarom 分別在 文章[25] 和 文章[23] 裏提出了,他們採用了不一樣的諸如 SVM 的機器學習的算法試圖從 緩存延遲的測量數據裏找到規律。
爲了有效地展開學習過程,攻擊者須要誘導受害者作一些操做,而後檢查哪些組被這個操做訪問到,詳見 算法2。
Let Si be the data structure matched to eviction set i 1. For each set i: (a) Iteratively access all members of Si to prime the cache set (b) Measure the time it takes to iteratively access all members of Si (c) Perform an interesting operation (d) Measure once more the time it takes to iteratively access all members of Si (e) If performing the interesting operation caused the access time to slow down considerably, then the operation was associated with cache set i.
由於 JavaScript 受到一系列的權限限制,實現步驟(c)是頗有挑戰的。與之造成對比的是 Apecechea 等人可以用一個空的 sysenter 調用來觸發一次細小的內核操做。爲了實現這個步驟,咱們必須調查 JavaScript 的運行時來發現有哪些函數會觸發有意思的行爲,例如文件訪問,網絡訪問,內存分配等等。 咱們還對那些運行時間相對較短,不會產生遺留的函數感興趣。由於遺留可能致使垃圾回收,進而影響步驟(d)的測量。Ho 等人在 文章[10] 中已經找到了這樣的 幾個函數。另一種方式是誘導用戶代替攻擊者執行一個特定的操做(好比在鍵盤上按一個鍵)。這個例子裏的學習過程多是結構化的(攻擊者知道受害者 將要執行的時機),也多是非結構化的(攻擊者只能假設系統一段時間內的響應緩慢是由受害者的操做致使的)。這兩種方法都被使用,詳見 章節4。
由於咱們的程序會一直檢測到由 JavaScript 運行時產生的活動,好比高性能的計時器的代碼,瀏覽器其它那些與當前執行調用無關的模塊的代碼,實際上咱們 經過調用兩個類似的函數並** 對比** 它們兩次活動性能分析的結果,以此來尋找相關的組。
正如 文章[23] 所示,LLC 訪問模式可被用來創建一個高帶寬的隱藏信道,有效的用來在同一臺宿主上的兩個虛擬機之間滲透敏感的信息。在咱們的攻擊模型裏, 攻擊者雖然不在同一臺宿主上的虛擬機裏,而是在一個網頁中,隱藏信道的動機不同,可是也頗有意思。
經由動機,咱們假設某個安所有門在追蹤犯罪大師 Bob 的蹤影。該部門經過釣魚項目在 Bob 的我的電腦上裝了一個被稱做 APT( Advanced Persistent Threat ) 的 軟件。APT 被設計用來記錄 Bob 的犯罪記錄併發送到部門的祕密服務器上。然而 Bob 很是的警覺,他使用了啓用了強制信息流跟蹤 (Information Flow Tracking ) [24] 的操做系統。操做系統的這一功能阻止了 APT 在訪問了可能含有用戶隱私數據的文件後再連上網絡。
在這種狀況下,只要 Bob 能被誘導訪問一個由安所有門控制的網頁,這個部門就能夠馬上採用基於 JavaScript 的高速緩存區攻擊。APT 能夠利用基於高速緩存區 的邊信道和惡意網站通訊,這樣就不用經過網絡傳輸用戶的隱私數據,進而不會觸發操做系統的信息流跟蹤功能。
這個研究案例受到了來自某個安所有門的 「RF retro-reflector」 設計的啓發,在這個設計裏一臺諸如麥克風的收集器,並不會把接收到的信號直接發送出去, 而是把接受的信號調製到由一個外部 」收集設備「 發送給它的 「照射信號」 上去。
隱藏信道的設計有兩個需求:第一,保持發送端的簡單,咱們尤爲不想讓它執行 章節2.1 中的移除集算法。第二,由於接收端的移除集是非典型的, 它應該足夠簡單,這樣接收端就能夠搜索到發送端的信號調製到了哪個組。
爲了知足這些需求,咱們的發射器/ APT 在本身的內存中分配了 4K 大小的數組,而且不斷地把收集到的數據轉換成對與這個數組的內存訪問的模式。這個 4K 大小 的數組覆蓋了緩存的 64 個組,這樣 APT 在每一個時間週期裏就能傳送 64比特 的數據。爲了能保證內存訪問可以被接收端定位,相同的訪問模式被重複 運用到數組的幾個拷貝上。 所以,高速緩衝區的大部分都會被執行到,與之造成對比的是 文章[23] 中的方法使用了典型的移除集,所以只會激活兩條緩存線。
接收端的代碼會對操做系統的內存作一個性能分析,而後搜索含有被 APT 調製後的數據所在的頁框。真正的數據會被從內存訪問的模式裏解調出來而後傳回服務器, 整個過程都不會違背操做系統對信息流跟蹤的保護。
咱們的攻擊模型假設發送端使用(相對較快的)機器語言編寫,而接收端是用 JavaScript 編寫。因此,咱們假設整個系統性能的限制因素是惡意網站的 採樣速度。
爲了評估隱藏信道的帶寬,咱們寫了一個小程序用預先設定好的模式來遍歷系統的內存(即含有單詞"Usenix"的比特圖)。 接下來,咱們用 JavaScript 高速緩存攻擊來嘗試尋找這一訪問模式,並測量 JavaScript 代碼所能達到的最大的頻率。
圖6 主機到主機的隱藏信道
圖6 顯示的內存譜圖捕捉到了這一隱藏信道的執行。隱藏信道的理論帶寬經過測量大約是 320kbps,這和 文章[23] 中用機器語言實現的跨虛擬機的隱藏信道 1.2Mbps 的帶寬比較吻合。
圖7 主機到虛擬機的隱藏信道
圖7 中的內存譜圖比較類似,但並非由運行在相同主機上的接收端代碼獲得的,而是在一臺虛擬機上獲得的(Firefox 34 瀏覽器,Ubuntu 14.01 系統, VMWare Fusion 7.1.0 )。儘管在這個場景下的高峯頻率只能到大約 8kbps,可是一個虛擬機中的網頁居然可以探測到底層的硬件,這着實讓人驚訝。
絕大多數關於高速緩存區攻擊的研究都假設攻擊者和受害者位於雲計算供應商數據中內心的同一臺機器上。這樣的機器通常不會配置成接收交互式的輸入, 因此該領域的大部分研究都聚焦於如何得到加密鑰匙或其它保密的狀態信息,譬如隨機數生成器的狀態[26]。 本文將研究怎麼利用高速緩存區攻擊來跟蹤用戶的行爲 ,這和咱們的攻擊模型更相關。咱們注意到 文章[20] 已經嘗試了利用 CPU 的一級緩存對系統負載進行細粒度的度量,以此跟蹤按鍵事件的方法。
本案例將演示一個惡意網站怎麼用高速緩存區攻擊去跟蹤用戶的活動。在接下來展現的的攻擊裏,咱們會假設用戶在一個背景標籤頁或窗口裏打開 了一個惡意網站的頁面,而且在另外一個標籤頁或是另一個徹底沒有互聯網鏈接的應用裏執行了一些敏感的操做。
咱們選擇了把焦點集中在鼠標操做和網絡活動上,由於操做系統負責處理它們的代碼沒有辦法被忽略不計。因此,咱們期待這些操做會在高速緩存區留下比較大的腳印。 並且正以下文所述,它們也很容易被 JavaScript 到處受限的安全模型所觸發。
兩種攻擊的結構比較相似。首先,進行性能分析,攻擊者用 JavaScript 探測每個組。接着,在訓練階段,待檢測的活動(網絡活動或鼠標操做)被觸發, 伴隨着對高速緩存區的高精度的採樣。在訓練階段一方面經過測量腳本直接觸發網絡活動(執行一個網絡請求),另外一方面是不停地在網頁上搖晃鼠標。
經過比較在訓練階段緩存區在閒時和忙時的活動,攻擊者能夠知道用戶操做會對應激活哪部分的組,而且訓練出一個關於組的分類器。最後, 在分類階段,攻擊者不停地監視這些有意思的組從而掌握用戶的活動。
咱們用一個基本的非結構化的訓練過程,即假設訓練過程當中系統進行的最集中的操做就是被測量的。爲了利用這點,咱們計算了隨着時間的 每次測量的 Hamming 權重(等於在某個週期內活躍組的個數),以後應用 k-meas 算法對測量數據作聚類。 而後計算每一個簇中每一個組的平均訪問延遲,從而算出每一個簇的中心。遇到未知的測量矢量,咱們會計算這個矢量和各個中心的歐幾里得距離, 並把它歸到最近的那一類。
在分類階段,咱們用命令行工具 wget 生成網絡流量,而且將鼠標移動到窗口之外。爲了得到網絡活動的真實數據,咱們同時用 tcp-dump 來測量系統的流量,而後把 tcp-dump 記錄的時間戳和分類器所檢測到時間戳聯繫起來。爲了得到鼠標操做的真實數據,咱們寫了一個頁面記錄全部 鼠標事件及其時間戳。須要強調的是,記錄鼠標活動的頁面並不在運行着測量代碼的瀏覽器(Firefox),而是運行在另外一個瀏覽器裏(Chrome)。
圖8 檢測到的網絡活動
圖9 檢測到的鼠標活動
活動測量的結果見 圖8 和 圖9 。兩個圖片的頂端都顯示了高速緩存區一個子集的實時活動。圖片的底端是分類器的輸出結果和外部收集的真實數據。 正如圖片展現的那樣,咱們異常簡單的分類器在識別鼠標操做和網絡活動方面很是有效。毫無疑問,使用更加 高級的訓練和分類技巧能夠進一步提升攻擊的效果。須要強調的是,鼠標操做的檢測器並不會檢測網絡活動,反之亦然。
分類器的測量頻率只有 500Hz。結果就是,它沒有辦法統計單個的包,而只能說明在一個階段裏活躍仍是不活躍。另外一方面,檢測鼠標活動的代碼要比 記錄真實數據的代碼採集到的事件多。這是由於 Chrome 瀏覽器對鼠標事件的頻率作了限制,大約是 60Hz。
Chen 等人在一篇著名的文章[5]中證實了對網絡活動的監測能夠做爲深度挖掘用戶行爲的奠定石 。雖然 Chen 等人假設攻擊者能夠在網絡層 監控受害者全部流入和流出的數據,可是這裏所展現的技術本質上可讓惡意網站監控用戶同時進行的網絡操做。攻擊能夠被更多的指標加強, 例如內存分配(見文[13]),DOM 佈局事件,磁盤寫操做等。
本文顯示了邊信道攻擊的範圍要比預期的大不少。本文提出的攻擊可針對互聯網上的大部分機器而不侷限於某些特定的攻擊場景。如此衆多的系統忽然間易受 邊信道攻擊意味着防止邊信道攻擊的算法和系統應當被普遍使用,而不能只是在某些特定狀況下。
咱們的攻擊須要一臺我的計算機,並配有 Intel CPU,使用了 Sandy Bridge, Ivy Bridge, Haswell 或者 Broadwell 的微架構。據 IDC 的數據顯示,2011年 之後售出的我的計算機80%都知足這一條件。更進一步,假設用戶使用的瀏覽器支持 HTML5 高精度計時器和類型數組的規範。表1 列舉了各個瀏覽器廠商支持這些 API 的最先的版本和易被攻擊的版本佔全球互聯網流量的比重,統計數據來自 StatCounter GlobalStatas 2015年一月份的報告。如表所示,目前市場上 80% 的瀏覽器 都沒法抵禦此類攻擊。
Browser brand | High Resolution Time Support | Typed Arrays Support | Worldwide prevalence |
---|---|---|---|
Internet Explorer | 10 | 11 | 11.77% |
Safari | 8 | 6 | 1.86% |
Chrome | 20 | 7 | 50% |
Firefox | 15 | 4 | 17.67% |
Opera | 15 | 12.1 | 1.2% |
Total | - | - | 83.03% |
攻擊可否取得效果取決於能不能用 JavaScript 高精度時間API 進行精準的測量。雖然 W3C 對這個API規範定義了高精度時間的單位是 「毫秒,並精確到千分之一」, 可是它並無給出該值的最高分辨率,實際上瀏覽器不一樣、操做系統不一樣這個值也會有所區別。舉個例子,咱們在測試過程當中發現 MacOS 上的 Safari 瀏覽器能夠精確 到納秒,而 Windows 上的 IE 瀏覽器只能精確到 0.8 微秒。 另外一方面, Chrome 瀏覽器在全部咱們測試的操做系統上給出的分辨率都是 1 微秒。
因此 圖3 中,單次緩存命中和緩存未命中的差異大概是 50 納秒,性能分析和測量的腳本在時間分辨率力度更細的操做系統上要稍加改動。 在性能分析階段,咱們沒有統計單次未命中的時間,而是重複讀取內存來放大時間的差異。 在測量階段,咱們雖然沒有辦法放大每次緩存未命中的時間,可是咱們能夠利用來自相同頁框的代碼一般會讓相鄰的組失效這一點。只要同一個頁框的64個組裏有20個 產生了緩存未命中,咱們的攻擊就能夠在哪怕是毫秒級的分辨率上進行。
咱們提出的這種攻擊還能夠很容易的運用到手機、平板等移動設備上。值得一提的是,安卓瀏覽器從 4.4 版本開始支持 高精度時間API 和 類型數組,但在 本文撰寫的時候 iOS Safari (8.1) 還不支持 高精度時間API。
本文描述的攻擊之因此可行,是由於它彙集了從微架構這一層到最終的 JavaScript 運行時設計和實現的的一些決定: 怎麼把物理內存的地址映射到組, 嵌套的高速緩存區架構,JavaScript 高速的內存訪問和高精度計時器;最後是 JavaScript 的權限模型。這裏的每一點上均可以採起一些緩解措施, 可是都會對系統的正常使用產生影響。
在微架構這層,修改物理內存到緩存線的映射方式能夠很是有效地阻止咱們的攻擊,即再也不用地址底12比特中的6個直接選擇一個組。相似的,換用非嵌套的 緩存微架構而不是用嵌套的,會讓咱們的代碼幾乎不願能精確地一級緩存中淘汰某項,使得測量更加困難。然而,這兩個設計決定當初被選擇正是爲了讓 CPU 的設計 和高速緩存的使用更高效,改變它們會讓其它不少的應用性能受到影響。再說了,修改 CPU 微架構可不是一件小事,由於升級已經部署的硬件是確定不行的。
在JavaScript這層,彷佛下降高精度計時器的分辨率就可讓攻擊更難發動。可是,高精度計時器的創建是爲了解決 JavaScript 開發者的實際須要的, 這些應用範圍可從音樂和遊戲再到加強現實和遠程醫療。
一個可能的權宜之計是限制應用只有在得到了用戶許可後才能訪問計時器(例如,經過顯示一個確認窗口)或者經過第三方的承認(例以下載自可信的 「app store」)。
一種有意思的方式是使用啓發式的性能分析來檢測和阻止此類攻擊。如 Wang 等人利用大量算法和按位指令的存在能夠預示這密碼學應用元素 [21] 的存在, 能夠注意到咱們的攻擊裏各類測量步驟訪問內存也會有必定的模式。由於現代的 JavaScript 的運行時,做爲性能分析引導優化的機制的一部分,已經可以 詳細的檢查代碼的運行時性能。因此 JavaScript 運行時應該可以在執行時發現有性能分析行爲的代碼而且相應的修改返回結果 (例如,在高精度計時器里加上抖動,或者動態的調整數組在內存中的位置等)。
在這篇論文裏,咱們展現瞭如何有效地經過可疑網頁發起針對微架構的邊信道攻擊,這種方式已被認爲是很是有效的。 與高速緩存區攻擊通常被用於密碼分析應用不一樣,本文介紹了它怎麼被用來有效地跟蹤用戶行爲。 邊信道攻擊的範圍已被拓展,這意味着設計新的安全系統時必定要考慮到對邊信道攻擊的反制措施。
咱們很感謝激 Henry Wong 對於 Ivy Bridge 緩存淘汰策略的研究和 Burton Rosenberg 對於頁和頁框的講解。
見原文
關於譯文
偶然看到這篇文章 美髮現新的瀏覽器攻擊模式:可監控全球八成PC, 很是驚訝 便隨手點開文章裏的原文鏈接 PDF,讀完有種腦洞大開的感受。論文知識點涉及計算機組成原理、虛擬化、 性能分析、JavaScript、HTML5規範等,都是我所感興趣的領域,再加上中招的是 老東家 的產品, 所以雖然我是安全領域的小白,但仍是嘗試精讀而且斗膽翻譯一下,不足之處歡迎你們批評指正。任何意見和建議請猛戳 issues
本文做者系OneAPM工程師編譯整理。OneAPM是中國基礎軟件領域的新興領軍企業。專一於提供下一代應用性能管理軟件和服務,幫助企業用戶和開發者輕鬆實現:緩慢的程序代碼和SQL語句的實時抓取。想閱讀更多技術文章,請訪問OneAPM官方技術博客。