蘋果公司前不久對 Safari
瀏覽器進行一次重大更新,這次更新完全禁用了第三方 Cookie
,這意味着,默認情況下,各大廣告商或網站將無法對你的個人隱私進行追蹤。而微軟和 Mozilla
等也紛紛採取了措施禁用第三方 Cookie
,但是由於這些瀏覽器市場份額較小,並沒有給市場帶來巨大的衝擊。
從 2017
年截至 2019
年底, Google
面臨的罰款總額已經超過 93 億歐元,其中一大原因便是侵犯用戶數據隱私。迫於巨大壓力,Google Chrome
官方團隊前不久也宣佈,爲了提升用戶隱私和安全,未來兩年將完全禁用第三方 Cookie
。
在完全不能寫入三方 Cookie
的情況下,將會對前端的數據讀寫方式,甚至是整個廣告行業帶來巨大影響。
Cookie 的意義
衆所周知,HTTP
協議是無狀態的協議,如果你在同一個客戶端向服務器發送多次請求,服務器不會知道這些請求來自同一客戶端。
這正是 HTTP
協議得以廣泛應用的原因,試想一下,如果它是有狀態協議,你必須要時刻與服務器建立鏈接,那麼如果連接意外斷開,整個會話就會丟失,重新連接之後一般需要從頭開始;而如果是無狀態協議,使得會話與連接本身獨立起來,這樣即使連接斷開了,會話狀態也不會受到嚴重傷害,保持會話也不需要保持連接本身。
如果 HTTP
協議只是用來訪問靜態文件,那不會有任何問題,但是如果你要爲廣大用戶提供更好的服務,服務器就需要知道每個請求具體來自於哪個用戶,比如你在逛淘寶的時候你只需要登錄一次,當你發起一次購買請求,服務器就已經知道你登錄過了,不會再讓你進行登錄。
所以 HTTP
協議需要佔用瀏覽器的一小塊存儲,存儲當前訪問用戶的一些 ”狀態“,然後每次發起 HTTP
請求,請求中就會攜帶這些狀態,從而讓服務器知道你是誰。 Cookie
出現的的意義就是爲了解決這個問題,讓無狀態的 HTTP
協議擁有一小塊記憶。
但是, Cookie
一經出現,就成了各大廣告和購物網站窺探用戶隱私的利器,他們使用第三方 Cookie
不斷獲取你的數據,那麼什麼第三方 Cookie
呢?
第三方 Cookie
如果是你正常的正在逛着天貓,天貓會把你的信息寫入一些 Cookie
到 .tmall.com
這個域下,然而打開控制檯你會看到,並不是所有 Cookie
都是 .tmall.com
這個域下的,裏面還有很多其他域下的 Cookie
,這些所有非當前域下的 Cookie
都屬於第三方 Cookie
,雖然你可能從來沒訪問過這些域,但是他們已經悄悄的通過這些第三方 Cookie
來標識你的信息,然後把你的個人信息發送過去了。
而 .tmall.com
這個域下的 Cookie
都屬於第一方 Cookie
,那麼爲什麼還需要第三方 Cookie
呢?再打開 taobao.com
,你會發現你已經不需要再登錄了,因爲淘寶、天貓都屬於阿里旗下的產品,阿里爲他們提供統一的登錄服務,同時,你的登錄信息也會存到這個統一登錄服務的域下,所以存到這個域下的 Cookie
就成了三方 Cookie
。
我們再打開已經完全禁用了第三方 Cookie
的 Safari
,發現只剩下 .tmall.com
這個域下的 Cookie
了。
這時你會發現即使你已經登錄了天貓,再訪問淘寶也還是需要登錄的,你已經無法享用這樣的功能了,而三方 Cookie
可不僅僅就這麼點用途,在 Web
開發中,三方 Cookie
的應用非常之廣,下面我們再來具體看幾個應用場景:
三方Cookie的用途
前端日誌打點
大多數 Web
站點都會引用一些第三方 SDK
來進行前端異常或性能監控,這些 SDK
會通過一些接口將監控到的信息上傳到他們的服務器。一般它們都需要標識每個用戶來方便排查問題或者統計 UV
數據,所以當你一此請求這個站點的時候,它們可能會在你的站點上 set
一個 Cookie
,後續所有的日誌上報請求都會帶上這個 Cookie
。
由於一般這些第三方 SDK
都是用於監控的通用服務,它們肯定會擁有自己獨立的域名,比如 log.com
,它在你的域名 mysite.com
下種下的 Cookie
就屬於第三方 Cookie
。
廣告營銷神器 - Facebook Pixel
在電商業務中,追蹤流量、導流量、轉換率、銷售額這些都是商家最關心的問題。這時候你就可以使用 Facebook Pixel
,簡單來說 Facebook Pixel
像素就是一串 JavaScript
代碼,可以追蹤廣告的轉化量、改進受衆定位、使廣告花費回報最大化。
當訪客進入到被設有 Facebook Pixel
的頁面時,便會觸發這段代碼。比如,查看了商品或者加入購物車, Facebook Pixel
便會向系統發送請求來記錄這些行爲,系統可以利用這些收到的行爲信息進一步的做追蹤和優化。
舉一個實際例子,我們進入一個國外的電商網站 Brava Fabrics
,你會發現已經被寫入了一堆 facebook.com
下的三方 cookie
:
我猜測這個 fr
應該就是用來標識我身份信息的 cookie
,然後點擊幾個頁面,在 network
裏面找到了幾個 facebook
發送的請求,下面是其中一個:
https://www.facebook.com/tr/?id=382444918612794&ev=PageView&dl=https%3A%2F%2Fbravafabrics.com%2Fcollections%2Fa-moment-of-bliss&rl=https%3A%2F%2Fbravafabrics.com%2F&if=false&ts=1586868288778&sw=1680&sh=1050&ud[ct]=eb045d78d273107348b0300c01d29b7552d622abbc6faf81b3ec55359aa9950c&ud[country]=eb045d78d273107348b0300c01d29b7552d622abbc6faf81b3ec55359aa9950c&v=2.9.15&r=stable&ec=0&o=30&fbp=fb.1.1586867082370.951509876&it=1586868284974&coo=false&rqm=GET
複製代碼
查看詳情你會發現,有下面幾個主要的參數:
dl: https://bravafabrics.com/collections/a-moment-of-bliss
rl: https://bravafabrics.com/
複製代碼
這時 facebook
已經知道了我從 https://bravafabrics.com/
來到了 https://bravafabrics.com/collections/a-moment-of-bliss
這個頁面,同時,這個請求會攜帶 fr=09wX7ui8MrvCh2SIa..BdNoGz.f.F6R.0.0.Belanb.AWXCDx
這個 Cookie
。
來到 facebook
,當你登錄後,facebook
會把剛剛這些 Cookie
和你的 facebook Id
關聯起來,然後他就可以好好的分析你的行爲了:
-
有人在你的網站上完成了購買。
-
有人註冊進行試用,或者以其他方式將自己標識爲你網站上的潛在客戶。
-
有人在你網站上的購買過程中輸入他們的付款信息。
-
有人將產品添加你網站上的購物車中。
-
有人選擇特定版本的產品,例如選擇某種顏色。
-
有人發起了結賬,但沒有付款
-
...
而如此強大的追蹤能力,只需要你複製一段 Facebook Pixel
的 JavaScript
腳本到你的頁面上就可以了。而這一切能力就建立在一個小小的 Cookie
的基礎上,因爲有了這個 Cookie
,Facebook
才能將這些行爲與它的賬號體系進行關聯。
無處不在的的 mmstat
再來看一個我們國內的例子,平時我們在國內的搜索引擎或視頻網站上搜索到一些東西,然後打開購物網站就可以收到各種你興趣的相關推薦,這已經是大衆習以爲常的事情了,各大購物網站、廣告商,會通過第三方 Cookie
收集你的年齡、性別、瀏覽歷史等從而判斷你的興趣喜好,然後帶給你精準的信息推薦。
比如,我們在瀏覽百度、優酷、天貓等網站時,都能看到幾個 .mmstat.com
這個域下的 Cookie
百度:
優酷:
天貓:
當你在百度、優酷、淘寶等進行一系列的操作時,.mmstat.com
已經悄悄的通過三方 Cookie
把你的個人信息運送到了他們那邊。 .mmstat.com
應該就是阿里旗下的大數據營銷平臺阿里媽媽旗下的域名(只是個人猜測)。打開阿里媽媽首頁,可以看到,其號稱是更懂消費者的數據金礦,已經建立起5億用戶的身份識別體系。你的每一次搜索、每一次購買、都會讓它變的更精準,下一次你就收到更精準的推薦。
當然,三方 Cookie
只是衆多獲取你喜好信息的一種方式,只不過這種方式更便捷,成本更低。
瀏覽器的策略
最近幾大瀏覽器針對 Cookie
策略的頻繁改動,意味着三方 Cookie
被全面禁用已經不遠了:
Firefox、Safari —— 默認禁用
在 Safari 13.1
、Firefox 79
版本中,三方 Cookie
已經被默認禁用,但是由於這些遊覽器市場份額較小,並沒有給市場帶來巨大的衝擊。因爲阿里的登錄信息是統一存在一個三方 Cookie
下的,淘寶剛開始的處理方式,甚至是彈個框出來,告訴用戶手動開啓三方 Cookie
:
但是這樣的處理方式對於龐大的用戶來講肯定體驗是極低的,解決方案可能是先將 Cookie
種在當前域下,所有就有了我們上面的測試結果,淘寶、天貓兩個網站需要登錄兩次。
但是三方 Cookie
做的事情遠不止這些,等到 Chrome
全面禁用之前,一定要提前作出改變。
Chrome —— SameSite Cookie
還好由於三方 Cookie
對 Google
的廣告業務影響較大,所以其沒有立即進行禁用,而是一直陸續修改一些小的策略來對三方 Cookie
進行限制,比如 SameSite
SameSite
是 Chrome 51
版本爲瀏覽器的 Cookie
新增的了一個屬性, SameSite
阻止瀏覽器將此 Cookie
與跨站點請求一起發送。其主要目標是降低跨源信息泄漏的風險。同時也在一定程度上阻止了 CSRF
攻擊。
SameSite
可以避免跨站請求發送 Cookie
,有以下三個屬性:
Strict
Strict
是最嚴格的防護,將阻止瀏覽器在所有跨站點瀏覽上下文中將 Cookie
發送到目標站點,即使在遵循常規鏈接時也是如此。因此這種設置可以阻止所有 CSRF
攻擊。然而,它的用戶友好性太差,即使是普通的 GET
請求它也不允許通過。
例如,對於一個普通的站點,這意味着如果一個已經登錄的用戶跟蹤一個發佈在公司討論論壇或電子郵件上的網站鏈接,這個站點將不會收到 Cookie
,用戶訪問該站點還需要重新登陸。
不過,具有交易業務的網站很可能不希望從外站鏈接到任何交易頁面,因此這種場景最適合使用 strict
標誌。
Lax
對於允許用戶從外部鏈接到達本站並使用已有會話的網站站,默認的 Lax
值在安全性和可用性之間提供了合理的平衡。 Lax
屬性只會在使用危險 HTTP
方法發送跨域 Cookie
的時候進行阻止,例如 POST
方式。同時,使用 JavaScript
腳本發起的請求也無法攜帶 Cookie
。
例如,一個用戶在 A 站點 點擊了一個 B 站點(GET請求),而假如 B 站點 使用了Samesite-cookies=Lax
,那麼用戶可以正常登錄 B 站點。相對地,如果用戶在 A 站點提交了一個表單到 B站點(POST請求),那麼用戶的請求將被阻止,因爲瀏覽器不允許使用 POST
方式將 Cookie
從A域發送到B域。
None
瀏覽器會在同站請求、跨站請求下繼續發送 Cookies
,不區分大小寫。
策略更新
在舊版瀏覽器,如果 SameSite
屬性沒有設置,或者沒有得到運行瀏覽器的支持,那麼它的行爲等同於 None
,Cookies
會被包含在任何請求中——包括跨站請求。
但是,在 Chrome 80+
版本中,SameSite
的默認屬性是 SameSite=Lax
。換句話說,當 Cookie
沒有設置 SameSite
屬性時,將會視作 SameSite
屬性被設置爲Lax
。如果想要指定 Cookies
在同站、跨站請求都被髮送,那麼需要明確指定 SameSite
爲 None
。具有 SameSite=None
的 Cookie
也必須標記爲安全並通過 HTTPS
傳送。這意味着所有使用 JavaScript
腳本收集用戶信息的請求默認將不能攜帶三方 Cookie
。
然而這個改動並不會造成太大的影響,它只是給各大網站提了一個信號,因爲你只需要把你想要發送的 Cookie
的屬性手動設置爲 none
即可:
真正可怕的是我們將無法直接指定 SameSite
爲 None
,只能用戶自己去選擇,這纔是真正的默認禁用。
Chrome
也宣佈,將在下個版本也就是 Chrome 83
版本,在訪客模式下禁用三方 Cookie
,在 2022
年全面禁用三方 Cookie
,到時候,即使你能指定 SameSite
爲 None
也沒有意義,因爲你已經無法寫入第三方 Cookie
了。
當三方 Cookie 被全面禁止
現在,我們想象一下,當瀏覽器禁用了三方 Cookie
,而我們又沒有作出任何改變的情況下,會發生什麼:
前端日誌異常
可能有一天你會突然發現,你的 UV
暴漲,但是 PV
卻沒有什麼變化,那可能是你的打點 SDK
使用的三方 Cookie
被禁用掉了。
這時這個 SDK
將無法在你的域下寫入一個三方 Cookie
,導致你的每次刷新頁面它都會帶一個新的 Cookie
回來,後端接受到的信號就是這些都是不同用戶的請求,所以都會計入 UV
。同時你在排查問題時,你也無法將用戶的行爲串聯起來,導致排查非常困難。
智能廣告推薦消失
上面我們提到,廣告服務通過你的年齡、性別、行爲來推斷你的喜好,從而推送給你精準的廣告,使用了三方 Cookie
來進行信息追蹤的廣告主將無法獲得你的這些喜好,從而無法推薦給你感興趣的廣告。
這時,廣告主只能在你當時的訪問環境進行預定義廣告,比如你正在訪問寵物網站,就給你推薦寵物用品等等。
同時,可能之前廣告主還會通過 Cookie
判斷你閱讀某個廣告的次數,一旦你閱讀同一個廣告多次但是沒有發生轉化,其就會停止向你推送該廣告。或者你已經購買過了這個商品,那你也不會再看到這個廣告了。如果沒有了頻率控制,那麼你可能要連續很多天盯着一個你永遠也不會去點的廣告,或者你會持續看到一個你已經購買過的產品廣告。
無法追蹤轉化率
當你查看一則廣告時,該廣告會在你的瀏覽器中放置一個 Cookie
,表示你已經看到它。如果隨後你進入轉化階段(購買、下載等),廣告主們需要能追蹤每一個他們投放到你網站上的轉化率,這樣他們才能計算投放的效果,從而作出優化策略,如果你無法再追蹤廣告轉化率了,那麼也很難再進行投放了。
當然,以上只是建立在你沒有進行任何改變的基礎上,距離全面禁用三方 Cookie
還有一年多的時間,這應該是一個足夠的時間讓你及時作出應對。
是好是壞
雖然,這對你帶來的可能是糟糕的廣告體驗,但是全面禁用三方 Cookie
對我們用戶來講肯定是一件好事,因爲你的信息不會被輕而易舉的就被別人追蹤了,你的隱私信息也不會容易被泄漏。
然而事情真的那麼簡單麼?貪婪的廣告商絕對不會直接放棄對你的信息追蹤,首先他們已經對你掌握了足夠多的信息,而且三方 Cookie
只是衆多獲取你信息的一種手段,只不過這種方法更方便簡單,爲了利益,他們一定會找到更多的替代方案:
使用一方 Cookie 替代 三方 Cookie
如果我們引入了一個三方的 SDK
,比如 google analytics
,說明我們對其是信任的,它對我們的信息收集追蹤都是在允許範圍內的。所以這些 SDK
依然可以使用第一方 Cookie
來完成用戶身份標識符。
比如,gtag.js
和 analytics.js
會設置以下 Cookie
用戶標識用戶信息:
但是,這些 Cookie
並不是第三方 Cookie
,而是設在你的域下的第一方 Cookie
,比如打開 twitter
的 Cookie
信息:
我們發現 _ga
、_gid
這兩個 Cookie
正是設置在其自己域下面的。
如果使用正常的 Set-Cookie
的形式,google analytics
是無法直接將 Cookie
設置到 twitter.com
這個域下面的,而且 google analytics
發起的日誌收集請求也無法攜帶 twitter.com
這個域下的 Cookie
。
打開 sdk
的代碼我發現裏面有使用 js 設置 Cookie
的代碼:
並且,收集日誌的請求中也又沒攜帶任何 Cookie
,而是把這信息帶在了參數中:
這樣的方式就模擬了使用三方 Cookie
標識用戶信息的過程,並且完全可以替代它。總而言之禁用三方 Cookie
對這種三方 SDK
的影響並不大,只要稍微改變一下思維即可。
當然,由於 Safari
和 Firefox
已經全面禁用了三方 Cookie
,一些廣告營銷服務也正在給出使用一方 Cookie
的替代方案,比如 Facebook Pixel
:
你允許了其讀取一方 Cookie
就意味着它能獲取你更多的數據,這意味着你需要承擔更大的用戶信息泄漏的風險。而且使用一方 Cookie
也不像使用三方 Cookie
那樣靈活,在某些場景下也是有很大限制的。
瀏覽器指紋
三方 Cookie
的主要作用是標識你的身份,從而在你下一次訪問時知道你是誰,那麼如果有一種技術直接就可以獲取你的唯一標識時,那麼就不需要再存儲 Cookie
了,這個技術就是 “瀏覽器指紋” 。
“瀏覽器指紋”是一種通過瀏覽器對網站可見的配置和設置信息來跟蹤 Web
瀏覽器的方法,瀏覽器指紋就像我們人手上的指紋一樣,每個人擁有一份接近於獨一無二的配置。
如果單單拿出一個配置來講可能很多人和你擁有一樣的配置,比如下面的:
- 系統版本:
-
我的系統版本是
Mac OS X 10_14_6
-
大約
11.91%
的人與我的配置相同 -
大約每
8
個人中有一個和我配置相同
-
Chrome
版本:-
我使用的瀏覽器是
Chrome
,並且版本是:81.0.4044.92
-
大約
0.08%
的人與我的配置相同 -
大約每
1250
個人中有一個和我配置相同
-
UTC+8
時間:-
我的
UTC+8
時間是2020.4.15 23:00:00
-
大約
2.30%
的人與我的配置相同 -
大約每
43
個人中有一個和我配置相同
-
如果單獨看每個配置,那他們都不能作爲你獨一無二的特徵,但是綜合起來看呢?比如就看這三項,三項的配置與你都相同的人的概率就會大大減小了。以上只是一些簡單的特徵,比如系統版本,瀏覽器版本,這些只需要一個簡單的 navigator.userAgent
屬性就可以拿到。
像這樣的屬性還有非常多個,他們可能來自 HTTP Header
、Javascript attributes
、瀏覽器插件
等等
HTTP Header
上面的 HTTP Header
中就包含了大量的定製化特性,可以看到每一項配置中與我相同的概率是非常低的,然而這些信息屬於普通的瀏覽器指紋,普通指紋可以理解爲容易被發現並且容易修改的部分,而且你也可以輕易的篡改他們,有些配置比如 User-Agent
、language
使用 JavaScript
的 navigator
對象獲取是最準確而且不會被篡改的。下面還有一些其他常見的 JavaScript
屬性:
Javascript attributes
這裏麪包含一些使用 Javascript
很容易獲取的一些配置:
-
Screen width
:屏幕寬度 -
Screen height
:屏幕高度 -
Cookies enabled
:是否允許Cookie
-
Content language
:語言信息 -
List of fonts
:字體信息 -
Timezone
:時區信息 -
Navigator properties:Navigator
對象中包含的屬性信息 -
...
以上這些信息非常容易獲取,而且帶有的信息較少,最後生成出來的指紋可能碰撞的概率就越大,實際上通過 JS
能獲取的遠不止這些,下面還有一些重複率非常低的指標:
Canvas 指紋
Canvas
是 HTML5
中用於在網頁上繪製 2D
圖形元素。瀏覽器在繪製圖形時,會調用操作系統的繪圖接口,即便使用 Cavans
繪製相同的元素,但是由於系統的差別,不同瀏覽器使用了不同的圖形處理引擎、不同的圖片導出選項、不同的默認壓縮級別、對抗鋸齒、次像素渲染等算法也不同。
具體獲取流程如下:在畫布上渲染一些文字,再用 toDataURL
轉換出來,你就會得到屬於你的 Cavans
指紋:
const canvas = document.getElementById("canvas-fingerprint");
const context = canvas.getContext("2d");
context.font = "18pt Arial";
context.textBaseline = "top";
context.fillText("canvas-fingerprint-test", 2, 2);
return canvas.toDataURL("image/jpeg");
複製代碼
上面的圖中可以看到,Canvas
指紋和我相同的概率是 <0.01%
的,可見這是一個在瀏覽器指紋中非常重要的指標。
WebGL
WebGL
是一種用於在網頁上呈現3D圖像的 JavaScript
瀏覽器API。網站可利用 WebGL
來識別你的設備指紋:
-
WebGL
報告 —— 完整的WebGL
瀏覽器報告表是可獲取、可被檢測的。在一些情況下,它會被轉換成爲哈希值以便更快地進行分析。 -
WebGL
圖像 —— 渲染和轉換爲哈希值的隱藏3D圖像。由於最終結果取決於進行計算的硬件設備,因此此方法會爲設備及其驅動程序的不同組合生成唯一值。這種方式爲不同的設備組合和驅動程序生成了唯一值。
WebRTC
WebRTC
(網頁實時通信,Web Real Time Communication
),是可以讓瀏覽器有音視頻實時通信的能力,通常被需要快速直接連接的網絡應用程序所應用。即便你使用了代理,網站也能借此獲取你真實的公共和本地IP地址。該插件可被用於泄漏你的本地 IP
地址或追蹤媒體設備。WebRTC
會暴露你的:
-
公共IP地址
-
本地IP地址
-
媒體設備的數量及其哈希值
CSS
就算用戶禁用了 JavaScript
,網站也可以通過純 CSS
來獲取到一些信息,比如這樣:
@media(device-width: 1920px) {
body {
background: url("https://example.org/1920.png");
}
}
複製代碼
通過統計 1920.png
這個圖片的請求日誌,便可知道有哪些用戶的窗口寬度是 1920px
。
UUID 的計算
綜合以上的指標特徵,可以計算出一個屬於你自己的唯一的 uuid
,這就是你的 "瀏覽器指紋" 了。當然,計算時不能簡單的將上述指標進行疊加,因爲某些指標在一些場景下聚合度比較高,每個指標帶來的信息量也不相同,一般每個指標都擁有一個自己的 "信息熵" :
信息熵(entropy)是接收的每條消息中包含的信息的平均量,熵越高,則能傳輸越多的信息,熵越低,則意味着傳輸的信息越少。
在計算 uuid
時,一般信息熵較大的指標會擁有較大的權重,這樣可以大大降低碰撞率,提高 uuid
的準確性。
當然,這些也不用你自己去挨個費勁的去獲取了,使用 clientjs
(https://github.com/jackspirou/clientjs
) 可以輕而易舉的幫你獲取這些指標,並最終獲取 uuid
:
// Create a new ClientJS object
const client = new ClientJS();
// Get the client's fingerprint id
const fingerprint = client.getFingerprint();
// Print the 32bit hash id to the console
console.log(fingerprint);
複製代碼
你也可以單獨獲取這些信息:
const client = new ClientJS();
client.getBrowserData();
client.getFingerprint();
client.getCustomFingerprint(...);
client.isCanvas();
client.getCanvasPrint();
client.getFlashVersion();
client.isSilverlight();
client.getSilverlightVersion();
// 。。。
複製代碼
參考
-
https://zhuanlan.zhihu.com/p/34591096
-
https://mp.weixin.qq.com/s/5-oObFPiRP6a5O49YsS9wg
-
https://juejin.im/post/5d97fb5ef265da5ba12cdea9