歡迎光臨
每天分享高質量文章

Cookie或將被替換!Chrome工程師提議新型HTTP狀態管理協議

問題


Cookie允許無狀態的HTTP協議支持有狀態會話,在web上,我們依靠Cookie實現了很多有趣的功能。即便如此,Cookie依然還是有很多問題:使用起來不夠安全,浪費資源,使用一種令人驚訝的方式追蹤用戶在網絡上的活動。

安全:這些年我們引入過很多的特性,試圖提供合理的安全屬性給那些關心安全的開發者,但也只是降低了安全問題而已:

  • Cookies對JavaScript來說預設是可用的(通過document.cookie),這使得一次XSS平滑升級能偷竊持久憑證(然後能使用Cookies在記憶體中產生類似於Spectre的有效攻擊)。雖然十年前引入了HttpOnly屬性,目前也只有大概8.31%的人使用Set-Cookie進行了設置。

  • 預設情況下,Cookie會被髮送到非安全的源,這會導致憑據被盜。Secure屬性將為安全的源Cookie鎖定,這很好!儘管如此,今天只有大概7.85%的人Set-Cookie進行了設置。

  • Cookies經常在請求發送者沒有任何跡象的情況下被設置。SameSite屬性用於減少CSRF風險,但是事實上,目前只有大概0.06%的人使用Set-Cookie進行了設置。

Cookies使用屬性來降低安全風險,然而它依然不符合我們對其他web資源設置的安全邊界。它們通過給定的註冊域名跨域訪問,它們忽略端口和scheme(意味著它們很容易被網絡攻擊者偽造),它們能縮小到詳細的路徑。這些特征使得它們很難落地,很難為平臺的其他地方降低同源策略起到激勵作用。

效率低:服務能通過一個給定的註冊域名儲存很多Cookie,並且很多Cookie可以通過HTTP請求被髮送。不同的瀏覽器供應商有不同的限制,但是它們都很高。例如Chrome,允許為每一個域名儲存180個Cookie,相當於硬碟上的724kB。幸運的是,如果請求頭中發送了很多的資料,服務器通常會出問題。Cookie濫用的情況事實上非常多:一般(未壓縮)的Cookie請求頭大小是409位元組,但是90%的請求是1589位元組,95%的請求是2549位元組,99%的請求是4601位元組(~0.1%的Cookie頭非常大,超過10kB)。

隱私:Cookies一方面能開啟監控(我希望我們可以在某種程度上解決這個問題,通過類似HTTP上Cookie的弊端描述的機制那樣放棄它),另一方面,用戶可能不瞭解全面跟蹤的事情。

註意:上面提到的所有統計資料來自於Chrome的2018年7月的資料。我非常歡迎其他瀏覽器供應商提供類似的資料,但是我假定它們在同一個數量級。

提議


讓我們通過為開發人員提供一條良好的路徑來解決上述問題,可以起到防範安全的作用。用戶代理能管理HTTP狀態,相當於在用戶這邊通過為用戶瀏覽的每個安全的源生成一個唯一的256位大小的Token。這個Token能作為結構化的HTTP請求頭,交付給源:

Sec-HTTP-State: token=*J6BRKagRIECKdpbDLxtlNzmjKo8MXTjyMomIwMFMonM*

這個標識或多或少像代理控制的Cookie,包含一些重要的差別:

  1. 代理管理Token值,而非服務端管理。

  2. Token將僅僅在網絡層可用,JavaScript不可用。

  3. 用戶代理將只為每個源產生一個256位大小的Token,並且將不會暴露任何它產生的Token給源。

  4. Token將不會被產生,或者傳遞給不安全的源。

  5. 預設情況下,Token將會在相同網站的請求中傳遞。

  6. Token持續存在,直到它被服務或者用戶或者代理重置。

這些差別可能不能改寫所有的用戶場景,但是一般情況下足夠了。對於不夠用的情況,我們支持開發者通過HTTP頭的Sec-HTTP-State-Options選項來進行控制。選項如下:

  1. 一些服務將必須跨站訪問它們的Token。另外一些服務可能希望將範圍縮小到同源請求。兩種方案都支持:

Sec-HTTP-State-Options: ..., delivery=cross-site, ...

或者

Sec-HTTP-State-Options: ..., delivery=same-origin, ...
  1. 一些服務將希望限制Token的生命周期。我們允許它們去設置TTL(單位秒):

Sec-HTTP-State-Options: ..., ttl=3600, ...

時間過期之後,這些Token的值將自動被重置。服務可能也希望去明確指定Token的重置(例如登出)。設置TTL為0能達到目的:

Sec-HTTP-State-Options: ..., ttl=0, ...

在任何情況下,都可以向當前運行的頁面通知用戶的狀態變化,以便執行重置操作。當重置發生,用戶代理能發送一個叫http-state-reset的訊息到源的BroadcastChannel(並且可能喚醒服務器響應用戶重置):

let resetChannel = new BroadcastChannel('http-state-reset'));
resetChannel.onmessage = e => { /* Do exciting cleanup here. */ };
  1. 對一些服務來說,代理產生Token將足夠狀態維護。他們能像一個會話標識一樣處理它,並且系結用戶狀態到服務端。另一些服務需要額外工作來保證信任Token的來源。為此,服務能產生一個唯一id,服務端使用它跟會話id關聯起來,並且通過HTTP響應頭傳遞它到代理:

Sec-HTTP-State-Options: ..., key=*ZH0GxtBMWA...nJudhZ8dtz*, ...

代理將儲存這個id,並且使用它去給資料集生成簽名,減少Token抓取的風險:

Sec-HTTP-State: token=*J6BRKa...MonM*, sig=*(HMAC-SHA265(key, token+metadata))*

舉例,使用已經定義的Signed Exchanges格式來簽名請求,除了重放攻擊之外,其他情況都很難使用被盜的令牌。在請求中包含時間戳可以減少重放攻擊的可能性。

註意:這種特定情況沒有被解決。我們需要去重新審視人們在系結Token等方面所做的工作,以確定正確的威脅模型是怎麼樣的。把它當成是一個方向去探索,這還不是一個深思熟慮的穩妥解決方案。

FAQ


繼續上面提到的三個方面,這個針對創建一個固化的狀態Token的建議,映射到與平臺其餘部分的相同安全原語,減少客戶端的傳輸成本,並且預設不支持跨站追蹤。

我們應該放棄Cookie?

當然不是!

那為什麼提出本方案?

Cookie是不好的,並且我們應該發現一種方式去放棄它。但是這需要花費一段時間。該提案旨在提供一種補充,即使在Cookie同時存在的情況下,也是有價值的方案,給我們一種推動開發者從一個方案增加另一個方案的能力。

與Cookie對比,它完全是一個新的東西?

不完全是。

開發人員可以通過設置像“__Host-token=value1; Secure; HttpOnly; SameSite=Lax; path=/”這樣的Cookie來獲得幾乎所有上面提到的屬性。這不是一個完美的方案,但它非常好。我瞭解到的現狀是,開發人員需要瞭解各種標誌和命名約定,才能通過Set-Cookie:token = value這樣的方式使用它。預設值很重要,這似乎是最簡單的事情。比起讓開發人員使用4個屬性,以及採用奇怪的命名約定來說,將它合併到1個屬性里更好。

我們還可以重新考慮服務器端狀態在代理上維護。我覺得使用用戶代理控制會話識別符號,而不是服務器設置的大量鍵值對,更優雅,更節約用戶的資源。

你期待大家怎麼從Cookie遷到這個方案上?

用戶代理可以通過在傳出的請求頭附加Sec-HTTP-State的方式,逐步遷移,來廣播對新功能的支持(預設情況下設置這個值,或允許開發人員根據上面的討論選擇性支持)。

開發人員可以開始將新機制用於其身份驗證基礎架構,這些機制最大程度地受益於源的作用域,與現有Cookie基礎架構並行。隨著時間的推移,他們可以建立一個他們所依賴的客戶端狀態串列,並開始在會話識別符號和狀態之間構建服務器端映射。一旦該機製成熟了,以逐步遷移的方式遷移。

最終,您可以想象讓開發人員能夠完全遷移,完全關閉其網站的Cookie(例如,通過Origin Manifests)。最終,我們還可以讓開發人員選擇使用Cookie而不是完全放棄。

在整個時間線的任何時刻,用戶代理都可以像HTTP上Cookie的弊端里提到的那樣,通過對Cookie子集進行限制來開始遷移。

對於多應用的源,這種遷移是不是很困難?

是的。這似乎是一個bug,又是一個功能。對於源和應用來說,1:1關係會更好。在同源的應用程式之間沒有安全邊界,我假設存在一個其他應用似乎沒有多大價值。鼓勵不同的應用在不同的源上運行,在它們的功能之間創建實際的隔離。

該提案是否對隱私屬性有重大改變?

不完全是。絕大多數沒有。也就是說,人們仍然可以使用這些Token來跟蹤源的用戶,就像他們今天使用Cookie一樣。人們需要通過設置Token的delivery成員來宣告這個意圖,有一點小的要求,需要用戶代理以某些方式對該宣告作出合理的響應,但就其本身而言,技術能力幾乎沒有變化。

儘管如此,它仍然比現狀有一些優勢。例如:

  1. 這些Token不會以明文形式發送,這降低了監控的風險。

  2. 用戶代理控制Token的值,這樣可以降低在用戶本地磁盤上暴露用戶敏感信息的風險,降低暴露您和用戶之間TLS終端的風險。

  3. 預設情況下,delivery選項會將Token限製為同源請求。假設我們遵循Cookie的SameSite 約定,用戶跨站訪問,需要明確說明Token可以跨站(此時用戶代理才會做出相應的處理)。

用戶可以如何管理用戶代理?

就像今天使用Cookie一樣,用戶可以選擇不將此Token發送到任何地方。用戶代理會朝著那個標的努力,但用戶也可以隨時選擇不適用用戶代理。

相關閱讀:

本文作者 Mike Wes,在Google的Chrome團隊就職,鄧啟明翻譯。轉載本文請註明出處,歡迎更多小伙伴加入翻譯及投稿文章的行列,詳情請戳公眾號選單「聯繫我們」。


高可用架構

改變互聯網的構建方式

長按二維碼 關註「高可用架構」公眾號

赞(0)

分享創造快樂