使用背景:
在一些業務中我們需要獲取一些匿名用戶的基本信息,以此來對用戶的行爲進行分析,然後針對一定的用戶羣體進行定向推薦。用戶信息採集一個重要的原則是要對用戶的行爲進行保密(不能把採集的信息進行明文存儲,一個思路是前端只存儲一個hasid具體的信息存在數據庫裏面)
基本思路:
1:生成一個識別唯一設備的標識碼
理想情況下是一個用戶對應一個識別碼,然而現實中我們可能最多做到一個瀏覽器對應一個用戶連一個設備對應一個用戶都做不到(不要問我爲什麼,前端能獲取的信息就那點,也沒有權限獲取用戶的硬件信息)。當用戶懂得技術的話把本地緩存和cookie一清我們連一個瀏覽器對應一個用戶都做不到了,考慮實際情況,大部分用戶都不會去刻意的清緩存的,因此我們這工作還是有價值的,能夠覆蓋80%以上 的情況就是有價值的,那麼我們如何生成這個唯一設備碼hashid呢?
- 時間戳+隨機數
萬能生成唯一碼的方法,這種方法幾乎不可能出現重複(除非平行時空的另一個你此時也在訪問同一個頁面)
var code=new Date().getTime()+Math.radom()
return hex_md5(code);//生成的唯一碼進行md5就是我們需要的設備號了
- canvas指紋
本文的重頭戲,canvas指紋登場了做個簡單介紹吧:
每一種瀏覽器都會使用不同的圖像處理引擎,不同的導出選項,不同的壓縮等級,所以每一臺電腦繪製出的圖形都會有些許不同,這些圖案可以被用來給用戶設備分配特定編號(指紋),也就是說可以用來識別不同用戶,一般情況下用戶不會去更換硬件設備,所以canvas可以很好的指定當前用戶的瀏覽器,但是當多個用戶的硬件設備,瀏覽器一致時就特別容易產生相同的指紋,所以canvas指紋並不能完全的替代cookie作爲用戶的身份驗證,但是可以作爲輔助的驗證信息。
識別範圍:瀏覽器
用途:輔助用戶驗證消息
缺點:原始的實現的方法在同一硬件設備同一瀏覽器容易重複
原始實現方法:
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
ctx.font = "24px Arial";
ctx.fillText("carnoc",22,33);
ctx.moveTo(0,0);
ctx.lineTo(100,100);
ctx.stroke();
var b64 = canvas.toDataURL().replace("data:image/png;base64,","");
return hex_md5(b64)//這裏又md5啦,md5後的識別碼就是我們需要的唯一設備號
通過定義相同的canvas行爲產生一個base64的數據,但是由於base64的數據不好存儲這裏使用js-md5進行編碼
問題:這樣簡易的canvas指紋在相同設備相同瀏覽器中重複率極高,所以要綜合其他因素進行判斷這裏有一個改進版的庫,裏面的判斷因素包括:
- 瀏覽器http請求中的用戶代理-navigator.userAgent
- 瀏覽器的語言(中文、英文……)-navigator.language
- 設備屏幕的色彩信息-screen.colorDepth
- 設備屏幕的寬高-screen.height screen.width
- 格林威治時間和本地時間之間的時差-Date().getTimezoneOffset()
- 是否支持sessionStorage-window.sessionStorage
- 是否支持localStorage-window.localStorage
- 是否支持indexdDB-window.indexedDB
- 是否支持-docment.body.addBehavior(IE5的一個屬性)
- 是否支持調用本地數據庫-window.openDatabase
- 瀏覽器所在系統的CPU等級-navigator.cupClass
- 客戶端的操作系統-navigator.platform
- 是否支持Do not track功能-navigator.doNotTrack
- 獲取瀏覽器部分插件信息-flash plugin、Adobe PDF reader、QuickTime、real players、ShockWave player、Windows media player、Silverlight、Skype
- canvas指紋
網傳的測試結果:
1.由於涉及設備以及瀏覽器的判定因素非常多,重複性很低,31臺設備皆無重複
但是可以設想,畢竟是通過各種屬性值去判斷唯一性,理想情況下如果兩臺設備相同瀏覽器各種設置也相同,還是會出現重複
2.也正因爲涉及的因素多,一旦設備系統更新 or 瀏覽器版本更新 or 瀏覽器關鍵插件有變化(版本更新 or 新增卸載關鍵插件) ,生成的ID都會改變,由於瀏覽器版本更新還是比較頻繁的,很容易失去之前跟蹤的用戶
參考資料:https://www.freebuf.com/news/40745.html
我的測試代碼:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fingerprintjs2/1.5.1/fingerprint2.min.js"></script>
new Fingerprint2().get(function(result, components){
resolve(hex_md5(result))
});
是一個異步的API,res裏面傳回得到的canvas指紋,改進版的唯一性得到大大的提高(親測的)
結論:
canvas指紋只能作爲一參考屬性去判斷設備的唯一性,不能只用這一個因素來判定設備唯一性。fingerPrint.js也不能取代cookie,但是可以作爲輔助,如果用戶清除了cookie的情況下,還可以通過fingerPrint.js跟蹤到該用戶重新set cookie
2:存儲設備碼
第一步的用戶的唯一設備號已經有了那麼我們如何進行安全永久(脆弱)的保存呢?
我使用的是cookie+localStorage進行保存的
cookie有一個好處,是可以在二級域名下共享cookie的如m.baidu.com和news.baidu.com,而本地緩存則做不到這樣就順便解決了同二級域名共享一個設備號的需求。
主要思路:
- 獲取的設備號存cookie,同時存本地緩存localStorage
- 若檢查到本地緩存的設備號與cookie不一致,以cookie爲準,同時更新本地緩存並把更改信息提交至後臺
- 每次進行訪問時檢查cookie和本地緩存有一個被清除了就使用另一個的設備號進行恢復
- 本地和cookie都沒有的話只能重新生成一個設備號進行存儲了(我也很絕望啊)
3:收集信息且提交
經過第二步我們知道了如何生成設備號和存儲設備號了那麼就應該進入第三步收集信息的環節了
具體要收集哪些信息看你的需求了(反正能得到的信息本來也不多)r如:設備分辨率,地理信息(移動端且開了GPS),瀏覽的網頁url,瀏覽時間等等,最後將你得到和信息和設備號hashid傳到後臺吧
總結:要進行一次匿名用戶信息一般需要三部
1:生成唯一設備碼
2:收集信息
3:存儲提交
如果以上的三步有更好的實現方法,歡迎討論分享。菜鳥一枚,出錯之處望指出,不勝感謝。