天天看點

通過浏覽器打開頁面時執行js腳本 改變浏覽器“指紋”

作者:Mutousoft

一般浏覽器先加載首頁,再請求關聯的js腳本檔案。不管你把js代碼嵌入在html中,還是獨立儲存為一個檔案,都必須等待首頁加載完成,js代碼加載完成後才能執行。網上有人說把js代碼放在head裡面,其實這樣并不影響腳本執行時機。因為js或html還沒有加載,何談執行js代碼。先看一下頁面加載資源的順序

通過浏覽器打開頁面時執行js腳本 改變浏覽器“指紋”

浏覽器加載頁面資源順序

再簡單分析一下onload事件的執行時機。

Document.onload

它是在結構和樣式加載完才執行js。【就是在html和css都完事以後才執行】

Window.onload

它不僅僅要在結構和樣式加載完,還要執行完所有的樣式、圖檔這些資源檔案,全部加載完才會觸發window.onload事件。

jquery中的ready

指定在DOM完全加載時要執行的函數。

也許你又會想到,先執行JavaScript,再打開頁面可以嗎?答案是否定的,因為執行完JavaScript後,執行結果儲存在變量中,當打開一個新的頁面時,js變量會被清空。

有什麼方法在頁面加載前就執行js代碼呢,單從網頁來考慮似乎無解,那就需要從浏覽器端入手。當輸入網址或點選連結導緻需要加載另一個頁面前就執行js代碼(注意隻是準備加載頁面,還沒有下載下傳一個字元)。這樣做可以在頁面加載前先給某些變量指派,且這個變量值在頁面加載完成後不會消失。

打開木頭浏覽器的項目管理視窗,建立一個腳本代碼步驟,并輸入需要執行的JavaScript代碼,選擇代碼執行時機為“頁面加載前執行”,儲存這個項目後,隻要執行一次這個項目(點選測試也可以),在浏覽器中打開任何網址時,都會先執行這段JavaScript代碼。如下圖所示,為友善體驗具體效果,設定一個彈窗代碼在頁面加載前執行。

通過浏覽器打開頁面時執行js腳本 改變浏覽器“指紋”

加載頁面前執行腳本

然後在浏覽器中輸入打開一個網址,此時頁面還沒有加載,就彈出了視窗。由于是模态彈窗,隻有點選确定後才會繼續加載頁面内容。頁面加載完成後,js變量值亦不會丢失。

通過浏覽器打開頁面時執行js腳本 改變浏覽器“指紋”

執行時機測試

如果需要停止在頁面加載前執行腳本代碼,隻需要再添加一個腳本代碼步驟,代碼為空,設定執行時機為“停止加載前執行”。當此步驟執行一次後,在浏覽器打開網頁就不會再執行腳本代碼彈出視窗了。

通過浏覽器打開頁面時執行js腳本 改變浏覽器“指紋”

停止加載前執行腳本

網頁加載前注入執行JavaScript腳本,具體有什麼作用呢?可以用于改變系統環境參數,比如修改螢幕分辨率;執行如下代碼後,網頁擷取分辨率時将得到預設值而非實際分辨率。

  1. screen.width = 1024;
  2. screen.height = 768;
  3. screen.availWidth = 1024;
  4. screen.availHeight =768;
  5. screen.availablewidth =1024;
  6. screen.availableheight =768;

還可以修改系統函數,替換函數功能。比如把下面這段代碼放在頁面加載前執行,改變系統的alert函數功能,那麼此頁面再執行alert就不會彈出視窗了。

  1. window.alert=function(txt){
  2. return txt;
  3. }

某些網站通過JavaScript功能函數采集“浏覽器指紋”,同樣可以通過修改功能函數,避免被網站跟蹤。比如在頁面加載前執行以下代碼,自動給canvas畫布指紋添加變化的噪聲,導緻頁面每次擷取的“浏覽器指紋”都不一樣。

  1. var inject = function () {
  2. const toBlob = HTMLCanvasElement.prototype.toBlob;
  3. const toDataURL = HTMLCanvasElement.prototype.toDataURL;
  4. const getImageData = CanvasRenderingContext2D.prototype.getImageData;
  5. //
  6. var noisify = function (canvas, context) {
  7. if (context) {
  8. const shift = {
  9. 'r': Math.floor(Math.random() * 10) - 5,
  10. 'g': Math.floor(Math.random() * 10) - 5,
  11. 'b': Math.floor(Math.random() * 10) - 5,
  12. 'a': Math.floor(Math.random() * 10) - 5
  13. };
  14. //
  15. const width = canvas.width;
  16. const height = canvas.height;
  17. if (width && height) {
  18. const imageData = getImageData.apply(context, [0, 0, width, height]);
  19. for (let i = 0; i < height; i++) {
  20. for (let j = 0; j < width; j++) {
  21. const n = ((i * (width * 4)) + (j * 4));
  22. imageData.data[n + 0] = imageData.data[n + 0] + shift.r;
  23. imageData.data[n + 1] = imageData.data[n + 1] + shift.g;
  24. imageData.data[n + 2] = imageData.data[n + 2] + shift.b;
  25. imageData.data[n + 3] = imageData.data[n + 3] + shift.a;
  26. }
  27. }
  28. //
  29. window.top.postMessage("canvas-fingerprint-defender-alert", '*');
  30. context.putImageData(imageData, 0, 0);
  31. }
  32. }
  33. };
  34. //
  35. Object.defineProperty(HTMLCanvasElement.prototype, "toBlob", {
  36. "value": function () {
  37. noisify(this, this.getContext("2d"));
  38. return toBlob.apply(this, arguments);
  39. }
  40. });
  41. //
  42. Object.defineProperty(HTMLCanvasElement.prototype, "toDataURL", {
  43. "value": function () {
  44. noisify(this, this.getContext("2d"));
  45. return toDataURL.apply(this, arguments);
  46. }
  47. });
  48. //
  49. Object.defineProperty(CanvasRenderingContext2D.prototype, "getImageData", {
  50. "value": function () {
  51. noisify(this.canvas, this);
  52. return getImageData.apply(this, arguments);
  53. }
  54. });
  55. //
  56. document.documentElement.dataset.cbscriptallow = true;
  57. };
  58. inject();

繼續閱讀