新的瀏覽器緩存策略變更:舍棄性能、確保安全
通常,緩存可以通過存儲數據來提高性能,從而可以更快后面相同數據的請求。例如,來自網絡的緩存資源可以避免頻繁的和服務器交互。緩存計算結果可以省去進行相同計算的時間。
在 Chrome 中,緩存機制以多種方式使用,HTTP 緩存就是一個示例。
Chrome 的 HTTP 緩存當前的工作方式
從 85 版開始,Chrome 會使用它們各自的資源URL作為緩存鍵來緩存從網絡獲取的資源。
下面我們來看幾個示例:
(1) Cache Key: { https://x.example/doge.png }
用戶訪問了頁面(https://a.example),然后請求了一個圖像(https://x.example/doge.png)。該圖像是從網絡請求的,瀏覽器會使用 https://x.example/doge.png 用作 key 進行緩存。
(2) Cache Key: { https://x.example/doge.png }
同一用戶訪問另一個頁面(https://b.example),這個頁面請求了相同的圖像(https://x.example/doge.png)。瀏覽器使用圖像 URL 作為 key ,檢查其 HTTP 緩存是否已經緩存了此資源。瀏覽器在其緩存中找之前緩存的資源,因此它使用了資源的緩存版本。
(3) Cache Key: { https://x.example/doge.png }
圖像是否從 iframe 中加載都沒有關系。如果網站 https://c.example 使用 iframe(https://d.example)訪問另一個網站,并且 iframe 中請求了相同的圖片(https://x.example/doge.png) ,則瀏覽器仍可以從緩存中加載圖片,因為所有頁面的緩存 key 均相同。
緩存機制存在的問題
從性能的角度來看,這種機制已經運行了很長時間了。但是,網站響應 HTTP 請求所花費的時間可以表明瀏覽器過去曾經訪問過相同的資源,這使瀏覽器容易受到安全和隱私的攻擊,比如:
- 檢測用戶是否訪問過特定站點:攻擊者可以通過檢查緩存是否具有特定于特定站點或一組站點的資源來檢測用戶的瀏覽歷史記錄。
- 跨站點搜索攻擊:攻擊者可以通過檢查特定網站使用的“無搜索結果”圖像是否在瀏覽器的緩存中來檢測用戶的搜索結果中是否包含任意字符串。
- 跨站點跟蹤:緩存可用于存儲類似 cookie 的標識符,作為跨站點跟蹤機制。
為了減輕這些風險,Chrome 將從 Chrome 86 開始對 HTTP 緩存進行分區。
緩存分區將如何影響 Chrome 的 HTTP 緩存?
通過緩存分區,除了資源 URL 外,還將使用新的 “網絡隔離密鑰” 來對緩存的資源進行密鑰設置。網絡隔離密鑰由頂級站點和當前 frame 中的站點組成。
注意:“站點”使用 “scheme://eTLD+1 ”識別,因此,如果請求來自不同的頁面,但是它們具有相同的 scheme 和有效的 eTLD+1,則它們將使用相同的緩存分區。
再次查看前面的示例,以了解緩存分區如何在不同的上下文中工作:
(1) Cache Key: { https://a.example, https://a.example, https://x.example/doge.png }
用戶訪問 https://a.example 請求圖像(https://x.example/doge.png)。在這種情況下,圖像是從網絡請求的,并使用由 https://a.example(頂級站點), https://a.example(當前 frame 中的站點)和 https://x.example/doge.png(資源URL)組成的元組作為 key 進行緩存。(請注意,當資源請求來主頁面時,網絡隔離密鑰中的頂級站點和當前 frame 中的站點是相同的。)
(2) Cache Key: { https://b.example, https://b.example, https://x.example/doge.png }
同一用戶訪問了 https://b.example 請求相同圖片(https://x.example/doge.png)。盡管在上一個示例中加載了相同的圖像,但是由于密鑰不匹配,因此不會被緩存命中。
(3) Cache Key: { https://a.example, https://a.example, https://x.example/doge.png }
現在用戶回到了 https://a.example ,但是這次圖像(https://x.example/doge.png)被嵌入到了 iframe 中。在這種情況下,圖片緩存的 key 和直接在主頁面加載的圖片的緩存 key 是相同的,因此可以使用之前緩存的圖片資源。
(4) Cache Key: { https://a.example, https://c.example, https://x.example/doge.png }
這個例子中,圖像在 https://c.example 的 iframe 中加載,在這種情況下,圖像是從網絡上下載的,因為緩存中找不到相同的密鑰。
(5) Cache Key: { https://a.example, https://c.example, https://x.example/doge.png }
如果域包含子域或端口號怎么辦?用戶訪問 https://subdomain.a.example ,其中嵌入的 iframe (https://c.example:8080) 請求了圖像的。
由于密鑰是基于 scheme://eTLD+1 創建的,因此將忽略子域和端口號。所以本次發生緩存命中。
(6) Cache Key: { https://a.example, https://c.example, https://x.example/doge.png }
如果 iframe 多次嵌套該怎么辦?用戶訪問 https://a.example,其中嵌入了一個 iframe(https://b.example),它又嵌入了另一個 iframe(https://c.example),這個 iframe 最終請求了圖像。
由于密鑰是從 https://a.example 加載資源的頂部 frame 和直接frame (https://c.example)獲取的,因此會發生緩存命中。
對現有網站的影響
這不是一個重大變化,但可能會影響某些網頁的性能。
例如,在許多站點上為大量可高度緩存的資源提供服務的站點(例如字體和流行的腳本)可能會看到其流量增加。同樣,使用此類服務的人可能會越來越依賴于它們。
下面是一些性能指標的變化:
- 整體緩存未命中率增加了約 3.6%
- FCP 增加約 0.3%
- 從網絡加載的字節的總體比例增加了約 4%
其他瀏覽器的行為
- Chrome: 使用頂級 scheme://eTLD+1 加 frame scheme://eTLD+1
- Safari: 使用頂級 eTLD+1
- Firefox: 計劃實施頂級 scheme://eTLD+1 然后也考慮像 Chrome 一樣增加第二個 key