什么是浏览器指纹
“浏览器指纹”是一种通过浏览器对网站可见的配置和设置信息来跟踪Web浏览器的方法,浏览器指纹就像我们人手上的指纹一样,具有个体辨识度,只不过现阶段浏览器指纹辨别的是浏览器。
人手上的指纹之所以具有唯一性,是因为每个指纹具有独特的纹路、这个纹路由凹凸的皮肤所形成。每个人指纹纹路的差异造就了其独一无二的特征。
那么浏览器指纹也是同理,获取浏览器具有辨识度的信息,进行一些计算得出一个值,那么这个值就是浏览器指纹。辨识度的信息可以是UA、时区、地理位置或者是你使用的语言等等,你所选取的信息决定了浏览器指纹的准确性。
对于网站而言,拿到浏览器指纹并没有实际价值,真正有价值的是这个浏览器指纹对应的用户信息。作为网站站长,收集用户浏览器指纹并记录用户的操作,是一个有价值的行为,特别是针对没有用户身份的场景。例如在一个内容分发网站上,用户A喜欢浏览二次元的内容,通过浏览器指纹记录这个兴趣,那么下次用户不需要登录即可向A用户推送二次元的信息。在个人PC如此普及的当下,这也是一种内容分发的方式。
对于用户而言,建立个人上网行为与浏览器指纹之间的联系或多或少都有侵犯用户隐私的意味,特别是将你的浏览器指纹和真实的用户信息相关联起来的时候。所幸的是这种方式对于用户的隐私侵犯比较有限、滥用用户行为也会透支用户对网站的好感。
第二代指纹追踪是设备指纹技术,发现 IP 背后的设备。通过 js 获取操作系统、分辨率、像素比等等一系列信息,传到后台计算,然后归并设备。
唯一性可以保证,但准确率很难完全保证。主要原因就是在跨浏览器指纹识别上面。跨浏览器之后,第二代技术中很重要的 canvas 指纹、浏览器插件指纹都变了,所以很难把跨浏览器指纹归并到同一设备上。
因为设备指纹相同,很大概率上是同一台设备;但是,设备指纹不同时,不一定不是同一台设备。
浏览器指纹怎么查看?
查看指纹地址:http://www.myjiancai.net/zhiwen/
接下来教大家如何修改浏览器指纹:
例如修改navigator全部参数
(function() {
'use strict';
function fakeActiveVRDisplays() { return "Not Spoofed"; }
function fakeAppCodeName() {
return "Mozilla";
}
function fakeAppName() {
return "Netscape";
}
function fakeAppVersion() {
return "5.0 (Windows)";
}
function fakeBattery() { return "Not Spoofed"; }
function fakeConnection() { return "Not Spoofed"; }
function fakeGeoLocation() { return "Not Spoofed"; }
function fakeHardwareConcurrency() {
return 1;
}
function fakeJavaEnabled() {
return false;
}
function fakeLanguage() {
// NOTE: TOR Browser uses American English
return "en-US";
}
function fakeLanguages() {
// NOTE: TOR Browser uses American English
return "en-US,en";
}
function fakeMimeTypes() { return "Not Spoofed"; }
function fakeOnLine() {
return true;
}
function fakeOscpu() {
return "Windows NT 6.1";
}
function fakePermissions() { return "Not Spoofed"; }
function fakePlatform() {
return "Win32";
}
function fakePlugins() {
return window.navigator.plugins;
}
function fakeProduct() {
return "Gecko";
}
function fakeServiceWorker() { return "Not Spoofed"; }
function fakeStorage() { return "Not Spoofed"; }
function fakeUserAgent() {
// NOTE: Current TOR User Agent as of 19 July 2017
// NOTE: This will need constant updating.
// NOTE: As TOR changes firefox versions each update,
// NOTE: Shape Shifter will need to keep up.
return "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0";
}
function fakeBuildID() {
return "20100101";
}
const fakeActiveVRDisplaysValue = fakeActiveVRDisplays();
const fakeAppCodeNameValue = fakeAppCodeName();
const fakeAppNameValue = fakeAppName();
const fakeAppVersionValue = fakeAppVersion();
const fakeBatteryValue = fakeBattery();
const fakeConnectionValue = fakeConnection();
const fakeGeoLocationValue = fakeGeoLocation();
const fakeHardwareConcurrencyValue = fakeHardwareConcurrency();
const fakeJavaEnabledValue = fakeJavaEnabled();
const fakeLanguageValue = fakeLanguage();
const fakeLanguagesValue = fakeLanguages();
const fakeMimeTypesValue = fakeMimeTypes();
const fakeOnLineValue = fakeOnLine();
const fakeOscpuValue = fakeOscpu();
const fakePermissionsValue = fakePermissions();
const fakePlatformValue = fakePlatform();
const fakePluginsValue = fakePlugins();
const fakeProductValue = fakeProduct();
const fakeServiceWorkerValue = fakeServiceWorker();
const fakeStorageValue = fakeStorage();
const fakeUserAgentValue = fakeUserAgent();
const fakeBuildIDValue = fakeBuildID();
Object.defineProperties(window.navigator, {
/*
activeVRDisplays: {
configurable: true,
enumerable: true,
get: function getActiveVRDisplays() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.activeVRDisplays");
return fakeActiveVRDisplaysValue;
}
},
*/
appCodeName: {
configurable: true,
enumerable: true,
get: function getAppCodeName() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.appCodeName");
return fakeAppCodeNameValue;
}
},
appName: {
configurable: true,
enumerable: true,
get: function getAppName() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.appName");
return fakeAppNameValue;
}
},
appVersion: {
configurable: true,
enumerable: true,
get: function getAppVersion() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.appVersion");
return fakeAppVersionValue;
}
},
// TODO: This is getBattery() now
/*
battery: {
configurable: true,
enumerable: true,
get: function getBattery() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.battery");
return fakeBatteryValue;
}
},
connection: {
configurable: true,
enumerable: true,
get: function getConnection() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.connection");
return fakeConnectionValue;
}
},
geolocation: {
configurable: true,
enumerable: true,
get: function getGeoLocation() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.geolocation");
return fakeGeoLocationValue;
}
},
*/
hardwareConcurrency: {
configurable: true,
enumerable: true,
get: function getHardwareConcurrency() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.hardwareConcurrency");
return fakeHardwareConcurrencyValue;
}
},
/*
javaEnabled: {
configurable: true,
enumerable: true,
value: function getJavaEnabled() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.javaEnabled");
return fakeJavaEnabledValue;
}
},
*/
language: {
configurable: true,
enumerable: true,
get: function getLanguage() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.language");
return fakeLanguageValue;
}
},
languages: {
configurable: true,
enumerable: true,
get: function getLanguages() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.languages");
return fakeLanguagesValue;
}
},
/*
mimeTypes: {
configurable: true,
enumerable: true,
get: function getMimeTypes() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.mimeTypes");
return fakeMimeTypesValue;
}
},
*/
onLine: {
configurable: true,
enumerable: true,
get: function getOnLine() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.onLine");
return fakeOnLineValue;
}
},
oscpu: {
configurable: true,
enumerable: true,
get: function getOscpu() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.oscpu");
return fakeOscpuValue;
}
},
/*
permissions: {
configurable: true,
enumerable: true,
get: function getPermissions() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.permissions");
return fakePermissionsValue;
}
},
*/
platform: {
configurable: true,
enumerable: true,
get: function getPlatform() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.platform");
return fakePlatformValue;
}
},
/*
plugins: {
configurable: true,
enumerable: true,
get: function getPlugins() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.plugins");
return fakePluginsValue;
}
},
*/
product: {
configurable: true,
enumerable: true,
get: function getProduct() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.product");
return fakeProductValue;
}
},
/*
serviceWorker: {
configurable: true,
enumerable: true,
get: function getServiceWorker() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.serviceWorker");
return fakeServiceWorkerValue;
}
},
storage: {
configurable: true,
enumerable: true,
get: function getStorage() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.storage");
return fakeStorageValue;
}
},
*/
userAgent: {
configurable: true,
enumerable: true,
get: function getUserAgent() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.userAgent");
return fakeUserAgentValue;
}
},
buildID: {
configurable: true,
enumerable: true,
get: function getBuildID() {
console.log("[ALERT] " + window.location.hostname + " accessed property Navigator.buildID");
return fakeBuildIDValue;
}
}
});
})();
另外关于浏览器硬件指纹,包括canvas,webgl,fonts,audio等,我来一一介绍:
HTML5中的canvas元素允许脚本进行2D形状和文本的渲染。通过这种方式,我们可以让一个程序输出打印图案两次,使用不同文字和颜色.来观察他们的区别.
字体探测指纹
告诉浏览器渲染同一个字符串(一个字符串包含所有字母)两次。 对于第一次强制浏览器使用它的一个备用字体。 根据设备上安装的操作系统和字体,备用字体不同。 对于第二次浏览器被要求使用常见的Arial字体,通过这种方式,我们可以获得其是哪一种操作系统.
通过WEBGL_debug_renderer_info 接口,获得产品名和供应商名
Platform(UA),Do Not Track & Ad blocker
以往检测字体,是通过falsh达到的,这里使用侧信道攻击,通过测量某个字符串的宽度和高度以确定字体
类型.
通过各种属性生成的指纹需要长期保存,防止被用户删除,或者可恢复,这就需要驻留技术,驻留技术比较成熟的是evercookie.其存储cookie的思路从以下几个方面
对于浏览器指纹,攻与防在不断的转换,目前浏览器指纹也不能绝对的标识一台主机,如果用户切换显卡或者双系统,虚拟机这些因素,那么目前的浏览器指纹就无法唯一标识了.未来随着新的HTML5技术不断更新,新的浏览器技术会提供更多的API.以及通过侧信道技术,在浏览器指纹会有新的突破