介紹
瀏覽器指紋簡單來說就是獲取瀏覽器一些具有辨識度的信息,計算得到的值,以此指紋信息可以對應此用戶。辨識度的信息可以是 UA、時區、地理位置或者是你使用的語言等其他的參數,信息越多並且信息的區別度越大,越能決定瀏覽器指紋的准確性。
直接使用 fingerprint2 庫
<script src="https://cdnjs.cloudflare.com/ajax/libs/fingerprintjs2/2.1.0/fingerprint2.js"></script>
<script>
requestIdleCallback(function () {
Fingerprint2.get(function (components) {
console.log(components) // an array of components: {key: ..., value: ...}
var values = components.map(function (component) { return component.value })
console.log(values);
var hash = Fingerprint2.x64hash128(values.join(''), 31)
console.log(hash)
})
})
</script>
計算了這么 29 個瀏覽器指征,能得到一個 32 個字符串(128位)的字符串,據說識別率能有 99.9% 據介紹 我不禁對他是怎么做的感到好奇
分析
信息熵(entropy)是接收的每條消息中包含的信息的平均量,熵越高,則能傳輸越多的信息,熵越低,則意味着傳輸的信息越少。
圖片摘自 掘金-是熊大啊-瀏覽器指紋追蹤技術簡述,下圖就是數個特征值的信息熵、重復概率和具體的值:
可見 UA,ACCEPT Headers,canvas 的熵值都很高,重復率也小。
canvas
Hash of canvas fingerprint 的信息熵最大有 15.8,按上圖所示,並且平均每 56922 個瀏覽器才會出現一個一樣的值。
使用 Canvas 繪制相同的元素,但是由於系統的差別,字體渲染引擎不同,對抗鋸齒、次像素渲染等算法也不同,canvas 將同樣的文字轉成圖片,得到的結果也是不同的。
獲取 Hash 的代碼簡化如下
function getCanvasFingerprint () {
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
var context = canvas.getContext("2d");
context.font = "18pt Arial";
context.textBaseline = "top";
context.fillText("Hello, user.", 2, 2);
return canvas.toDataURL("image/jpeg");
}
getCanvasFingerprint()
我分別再 Chrome 和 Edge 上運行
可以再 ,可以點擊這里測試一下你Canvas指紋。我測試的結果碰撞率約莫 0.05%。
258 of 528769 user agents have the same signature
當然 fingerprintjs2 計算 canvas 的代碼更完善,請參照fingerprintjs2 的 getCanvasFp 方法 ,筆者測試按照他生成的 dataUrl 有 33.4kb。
怎么計算?
上文 Fingerprint2 的調用,能窺見一些信息,把所有的指征包括 UA,ACCEPT Headers,canvas 等其他 29 項都直接拼接成一個字符串傳給了 Fingerprint2.x64hash128 方法,
分析其方法,使用了 MurmurHash3 哈希算法,筆者查閱得知我們熟知的 MD5、SHA1 是加密哈希算法,而 MurmurHash3 是非加密的哈希算法。如果數據量小,或者不太在意哈希碰撞概率,甚至希望生成的哈希值更小,都推薦使用非加密的哈希算法。有 128 位和 32 位兩個版本,128 位版本的運算速度是 MD5 的十倍,此方法就選了 128 位的。
去 MurmurHash online 在線計算一下從 Fingerprint2 那邊得到的指征拼接字符串
結果和上文的 Fingerprint2 運算結果一致
思考
這么計算在同一機器的不同瀏覽器得到的 hash 不一致,那么跨瀏覽器的指紋識別怎么做,請參照這篇 http://yinzhicao.org/TrackingFree/crossbrowsertracking_NDSS17.pdf