浏览器指纹 Browser Fingerprint

浏览器指纹 Browser Fingerprint

2023-12-11
暂无分类

浏览器指纹在线检测工具:链接

指纹原理:js通过浏览器拿到各种参数然后进行计算(拼接、hash、md5......),最终会得到一个string,这个string就是指纹

修改指纹的原理也很简单,hook一下相关参数返回值就行

指纹屏蔽并不是通用的,要分析网站上传了哪些数据,只需要把上传的数据fake掉就行了

更多chrome插件列表:https://mybrowseraddon.com/

canvas(换浏览器失效)

https://chromewebstore.google.com/detail/canvas-fingerprint-defend/lanfdkkpgfjfdikkncbnojekcppdebfp?hl=en

(function canvas() {
    const getImageData = CanvasRenderingContext2D.prototype.getImageData;
    //
    const noisify = function (canvas, context) {
        if (context) {
            const shift = {
                'r': Math.floor(Math.random() * 10) - 5,
                'g': Math.floor(Math.random() * 10) - 5,
                'b': Math.floor(Math.random() * 10) - 5,
                'a': Math.floor(Math.random() * 10) - 5
            };
            //
            const width = canvas.width;
            const height = canvas.height;
            //
            if (width && height) {
                const imageData = getImageData.apply(context, [0, 0, width, height]);
                //
                for (let i = 0; i < height; i++) {
                    for (let j = 0; j < width; j++) {
                        const n = ((i * (width * 4)) + (j * 4));
                        imageData.data[n + 0] = imageData.data[n + 0] + shift.r;
                        imageData.data[n + 1] = imageData.data[n + 1] + shift.g;
                        imageData.data[n + 2] = imageData.data[n + 2] + shift.b;
                        imageData.data[n + 3] = imageData.data[n + 3] + shift.a;
                    }
                }
                context.putImageData(imageData, 0, 0);
            }
        }
    };
    //
    HTMLCanvasElement.prototype.toBlob = new Proxy(HTMLCanvasElement.prototype.toBlob, {
        apply(target, self, args) {
            noisify(self, self.getContext("2d"));
            //
            return Reflect.apply(target, self, args);
        }
    });
    //
    HTMLCanvasElement.prototype.toDataURL = new Proxy(HTMLCanvasElement.prototype.toDataURL, {
        apply(target, self, args) {
            noisify(self, self.getContext("2d"));
            //
            return Reflect.apply(target, self, args);
        }
    });
    //
    CanvasRenderingContext2D.prototype.getImageData = new Proxy(CanvasRenderingContext2D.prototype.getImageData, {
        apply(target, self, args) {
            noisify(self.canvas, self);
            //
            return Reflect.apply(target, self, args);
        }
    });
})()

webgl(换浏览器可能不失效)

https://chromewebstore.google.com/detail/webgl-fingerprint-defende/olnbjpaejebpnokblkepbphhembdicik?hl=en

UNMASKED_VENDOR_WEBGL和UNMASKED_RENDERER_WEBGL的值要改一下,这个网站可以检测

(function webgl() {
    const config = {
        "random": {
            "value": function () {
                return Math.random();
            }, "item": function (e) {
                let rand = e.length * config.random.value();
                return e[Math.floor(rand)];
            }, "number": function (power) {
                let tmp = [];
                for (let i = 0; i < power.length; i++) {
                    tmp.push(Math.pow(2, power[i]));
                }
                /*  */
                return config.random.item(tmp);
            }, "int": function (power) {
                let tmp = [];
                for (let i = 0; i < power.length; i++) {
                    let n = Math.pow(2, power[i]);
                    tmp.push(new Int32Array([n, n]));
                }
                /*  */
                return config.random.item(tmp);
            }, "float": function (power) {
                let tmp = [];
                for (let i = 0; i < power.length; i++) {
                    let n = Math.pow(2, power[i]);
                    tmp.push(new Float32Array([1, n]));
                }
                /*  */
                return config.random.item(tmp);
            }
        }, "spoof": {
            "webgl": {
                "buffer": function (target) {
                    let proto = target.prototype ? target.prototype : target.__proto__;
                    //
                    proto.bufferData = new Proxy(proto.bufferData, {
                        apply(target, self, args) {
                            let index = Math.floor(config.random.value() * args[1].length);
                            let noise = args[1][index] !== undefined ? 0.1 * config.random.value() * args[1][index] : 0;
                            //
                            args[1][index] = args[1][index] + noise;
                            //
                            return Reflect.apply(target, self, args);
                        }
                    });
                }, "parameter": function (target) {
                    let proto = target.prototype ? target.prototype : target.__proto__;
                    //
                    proto.getParameter = new Proxy(proto.getParameter, {
                        apply(target, self, args) {
                            //
                            if (args[0] === 3415) return 0; else if (args[0] === 3414) return 24; else if (args[0] === 36348) return 30; else if (args[0] === 7936) return "WebKit"; else if (args[0] === 37445) return "Google Inc."; else if (args[0] === 7937) return "WebKit WebGL"; else if (args[0] === 3379) return config.random.number([14, 15]); else if (args[0] === 36347) return config.random.number([12, 13]); else if (args[0] === 34076) return config.random.number([14, 15]); else if (args[0] === 34024) return config.random.number([14, 15]); else if (args[0] === 3386) return config.random.int([13, 14, 15]); else if (args[0] === 3413) return config.random.number([1, 2, 3, 4]); else if (args[0] === 3412) return config.random.number([1, 2, 3, 4]); else if (args[0] === 3411) return config.random.number([1, 2, 3, 4]); else if (args[0] === 3410) return config.random.number([1, 2, 3, 4]); else if (args[0] === 34047) return config.random.number([1, 2, 3, 4]); else if (args[0] === 34930) return config.random.number([1, 2, 3, 4]); else if (args[0] === 34921) return config.random.number([1, 2, 3, 4]); else if (args[0] === 35660) return config.random.number([1, 2, 3, 4]); else if (args[0] === 35661) return config.random.number([4, 5, 6, 7, 8]); else if (args[0] === 36349) return config.random.number([10, 11, 12, 13]); else if (args[0] === 33902) return config.random.float([0, 10, 11, 12, 13]); else if (args[0] === 33901) return config.random.float([0, 10, 11, 12, 13]); else if (args[0] === 37446) return config.random.item(["Graphics", "HD Graphics", "Intel(R) HD Graphics"]); else if (args[0] === 7938) return config.random.item(["WebGL 1.0", "WebGL 1.0 (OpenGL)", "WebGL 1.0 (OpenGL Chromium)"]); else if (args[0] === 35724) return config.random.item(["WebGL", "WebGL GLSL", "WebGL GLSL ES", "WebGL GLSL ES (OpenGL Chromium"]);
                            //
                            return Reflect.apply(target, self, args);
                        }
                    });
                }
            }
        }
    };
    //
    config.spoof.webgl.buffer(WebGLRenderingContext);
    config.spoof.webgl.buffer(WebGL2RenderingContext);
    config.spoof.webgl.parameter(WebGLRenderingContext);
    config.spoof.webgl.parameter(WebGL2RenderingContext);
})()

另一个版本:我自己写的。原理:在Extension列表末尾添加一个随机的字符串

(function webgl() {
    const getSupportedExtensions = WebGLRenderingContext.prototype.getSupportedExtensions;

    Object.defineProperty(WebGLRenderingContext.prototype, "getSupportedExtensions", {
        "value": function () {
            const extensions = getSupportedExtensions.apply(this) || [];
            const randomExtension = 'random-extension-' + Math.random().toString(36).substr(2, 10);
            extensions.push(randomExtension);
            return extensions;
        }
    });
})()

font(多个因素相关,换浏览器可能依旧生效)

https://chromewebstore.google.com/detail/font-fingerprint-defender/fhkphphbadjkepgfljndicmgdlndmoke?hl=en

(function font() {
    const rand = {
        "noise": function () {
            const SIGN = Math.random() < Math.random() ? -1 : 1;
            return Math.floor(Math.random() + SIGN * Math.random());
        }, "sign": function () {
            const tmp = [-1, -1, -1, -1, -1, -1, +1, -1, -1, -1];
            const index = Math.floor(Math.random() * tmp.length);
            return tmp[index];
        }
    };
    //
    Object.defineProperty(HTMLElement.prototype, "offsetHeight", {
        "get": new Proxy(Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight").get, {
            apply(target, self, args) {
                try {
                    const height = Math.floor(self.getBoundingClientRect().height);
                    const valid = height && rand.sign() === 1;
                    const result = valid ? height + rand.noise() : height;
                    return result;
                } catch (e) {
                    //return Reflect.apply(target, self, args);
                }
            }
        })
    });
    //
    Object.defineProperty(HTMLElement.prototype, "offsetWidth", {
        "get": new Proxy(Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetWidth").get, {
            apply(target, self, args) {
                const width = Math.floor(self.getBoundingClientRect().width);
                const valid = width && rand.sign() === 1;
                const result = valid ? width + rand.noise() : width;
                return result;
            }
        })
    });
})()

audio(换浏览器失效)

https://chromewebstore.google.com/detail/audiocontext-fingerprint/pcbjiidheaempljdefbdplebgdgpjcbe?hl=en

(function audio() {
    const context = {
        "BUFFER": null, "getChannelData": function (e) {
            e.prototype.getChannelData = new Proxy(e.prototype.getChannelData, {
                apply(target, self, args) {
                    const results_1 = Reflect.apply(target, self, args);
                    //
                    if (context.BUFFER !== results_1) {
                        context.BUFFER = results_1;
                        //
                        for (let i = 0; i < results_1.length; i += 100) {
                            let index = Math.floor(Math.random() * i);
                            results_1[index] = results_1[index] + Math.random() * 0.0000001;
                        }
                    }
                    //
                    return results_1;
                }
            });
        }, "createAnalyser": function (e) {
            e.prototype.__proto__.createAnalyser = new Proxy(e.prototype.__proto__.createAnalyser, {
                apply(target, self, args) {
                    const results_2 = Reflect.apply(target, self, args);
                    //
                    results_2.__proto__.getFloatFrequencyData = new Proxy(results_2.__proto__.getFloatFrequencyData, {
                        apply(target, self, args) {
                            const results_3 = Reflect.apply(target, self, args);
                            //
                            for (let i = 0; i < arguments[0].length; i += 100) {
                                let index = Math.floor(Math.random() * i);
                                arguments[0][index] = arguments[0][index] + Math.random() * 0.1;
                            }
                            //
                            return results_3;
                        }
                    });
                    //
                    return results_2;
                }
            });
        }
    };
    //
    context.getChannelData(AudioBuffer);
    context.createAnalyser(AudioContext);
    context.createAnalyser(OfflineAudioContext);
})()

禁用WebRTC(防止真实IP泄漏)

插件:https://chromewebstore.google.com/detail/webrtc-control/fjkmabmdepjfammlpliljpnbhleegehm

在线测试:https://webbrowsertools.com/test-webrtc-leak/

其他指纹

  1. browser fingerprint:以上任意指纹改变,这个也会改变

  2. screen fingerprint:更换屏幕尺寸或分辨率,就失效

低成本指纹浏览器

firefox+CanvasBlocker+MultiAccountContainer+ContainerProxy

THE END
0/500
暂无评论