系統安全與漏洞利用

快取旁路(cache side channel)

CPU 快取是一小塊快速記憶體,把最近用過的資料留在近處,使對同一位址的第二次存取比第一次快得多。那個速度差很有用——但它也是一個洩漏:藉由量測一次存取有多快,你能判斷那筆資料是否最近被碰過。快取旁路把這個「它被快取了嗎?」的時間,化成一扇窺看另一段程式碼一直在存取哪些依秘密而定之記憶體的窗。

兩個經典技術讓這變得具體。在 Flush+Reload(需要共享記憶體,例如攻擊者與受害者之間共享的函式庫)中:攻擊者把某條特定快取列從快取中清除(clflush),讓受害者執行,接著「重新載入」同一條列並計時。快的重新載入代表受害者碰過那條列(它又被快取了);慢的代表沒碰。如果受害者的程式碼存取 table[secret],攻擊者就藉由看哪條列快速回來,得知是哪個項目——進而得知秘密。在 Prime+Probe(不需共享)中:攻擊者用自己的資料填滿一個快取組(prime),讓受害者執行,接著重新存取自己的資料並計時(probe);現在變慢的列是被受害者「逐出」的,揭露受害者用了哪些快取組。無論哪種,一連串快/慢的時間,跨多次執行蒐集以壓過雜訊,就重建出依秘密而定的記憶體存取,例如密碼學表查找所用的索引。

它之所以重要,是因為它跨越看似密不透風的邊界洩漏:行程之間、沙箱與主機之間、甚至同一顆實體 CPU 上的虛擬機之間,而完全不違反任何記憶體權限。它也是 Spectre 與 Meltdown 底下的量測引擎——那些攻擊誘使 CPU 推測性地把一個秘密載入快取,再透過正是這個 Flush+Reload 把戲把它讀出來。誠實的說法:快取旁路難以完全封閉,因為快取是效能的根本;緩解措施包括在敏感程式碼中採用定時、與資料無關的記憶體存取樣式、快取分割、以及不把不受信任的租戶共置在共享硬體上——每一項都付出效能代價。

// Flush+Reload,探測一條列: clflush(&probe); // 1. 把 probe 逐出快取 run_victim(); // 2. 若秘密位元被設,受害者可能存取 probe t0 = rdtsc(); x = probe; // 3. 重新載入並計時 t1 = rdtsc(); // (t1 - t0) 小 => 受害者碰過它(已快取)=> 那個秘密位元被設了

快速的重新載入洩露了受害者存取過那條列——透過快取時間洩漏了秘密的一個位元。

沒有任何記憶體權限規則被打破——洩漏純粹是時間——所以它跨越行程與虛擬機邊界;快取旁路也是讓 Spectre 與 Meltdown 變得可觀測的讀出機制。

又稱
cache timing attackFlush+ReloadPrime+Probe快取時間攻擊快取側通道