使用浏览器指纹做设备唯一标志

背景:

需要做一个登录安全校验功能, 非常用设备登录网站时, 弹出安全验证框进行验证

调研

设备/浏览器唯一标志 ID 调研

背景:

产品要求新登录设备弹出安全验证框, 因此需要标识每一台设备, 但是前端做不到设备级, 只能尝试标识浏览器

方案:

浏览器本地存储直接设置标识

往 localStorage 中存入一个新变量, 值为登录时间 + 随机数, 之后始终不清除此数据, 每次登录时取该数据一起发给后端, 后端判断与数据库中数据是否一致

优点:

  1. 最简单

缺点:

  1. 用户可以通过浏览器控制台自己修改数据
  2. 隐身模式需要重新校验
  3. 本地存储被清除需要重新校验

使用浏览器音频 API 标识客户

https://audiofingerprint.openwpm.com/

搜集浏览器音频播放的特征值, 计算得到唯一标志

优点:

  1. 纯前端实现, 前端直接使用页面上的代码即可实现
  2. 不同版本的 chrome 浏览器生成的标识相同
  3. 隐身模式/清除本地存储, 标识不变

缺点:

  1. 是否有版权问题?
  2. 公司内同一批同配置电脑 + 驱动 + 同一款浏览器, 可能会重复(再加个随机数? 比如时间之类的?)

使用开源库

https://github.com/fingerprintjs/fingerprintjs/

查询浏览器属性(包括并不限于音频, 画布, 字体, 屏幕, 操作系统, 设备名称等信息), 从中计算出标识

优点:

  1. 纯前端实现, 前端直接引用库即可实现
  2. 隐身模式/清除本地存储, 标识不变

缺点:

  1. 不同版本的 chrome 浏览器生成的标识不同
  2. 还是可能会重复(再加个随机数? 比如请求时间之类的?)

使用前者的升级版

开源版和专业版对比: https://dev.fingerprintjs.com/docs/pro-vs-open-source

demo: https://fingerprintjs.com/demo/

优点:

  1. 在服务器端处理所有信息,将浏览器指纹识别与大量辅助数据(IP 地址、访问时间模式、URL 更改等)相结合,能够可靠地对拥有相同设备的不同用户进行重复数据删除,从而实现 99.5% 的识别准确率

缺点:

  1. 调用 api 次数超过 20K/月, 则开始收费

最终代码:

// 生成浏览器指纹, 目前仅使用了 audio api 生成指纹, 参考 https://audiofingerprint.openwpm.com/ 网站源码
export const gen_fingerPrint = (useFullPrint = true) => {
    return new Promise((resolve, reject) => {
        try {
            let shortPrint = '';
            let fullPrint = '';

            const context = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 44100, 44100);

            const pxi_oscillator = context.createOscillator();
            pxi_oscillator.type = 'triangle';
            pxi_oscillator.frequency.value = 1e4;

            // Create and configure compressor
            const pxi_compressor = context.createDynamicsCompressor();
            pxi_compressor.threshold && (pxi_compressor.threshold.value = -50);
            pxi_compressor.knee && (pxi_compressor.knee.value = 40);
            pxi_compressor.ratio && (pxi_compressor.ratio.value = 12);
            pxi_compressor.reduction && (pxi_compressor.reduction.value = -20);
            pxi_compressor.attack && (pxi_compressor.attack.value = 0);
            pxi_compressor.release && (pxi_compressor.release.value = 0.25);

            // Connect nodes
            pxi_oscillator.connect(pxi_compressor);
            pxi_compressor.connect(context.destination);

            // Start audio processing
            pxi_oscillator.start(0);
            context.startRendering();
            context.oncomplete = function (evnt) {
                let pxi_output = 0;
                const sha1 = CryptoJS.algo.SHA1.create();
                for (let i = 0; i < evnt.renderedBuffer.length; i++) {
                    sha1.update(evnt.renderedBuffer.getChannelData(0)[i].toString());
                }
                const hash = sha1.finalize();
                // Fingerprint using DynamicsCompressor (hash of full buffer):
                fullPrint = hash.toString(CryptoJS.enc.Hex);

                for (let i = 4500; i < 5e3; i++) {
                    pxi_output += Math.abs(evnt.renderedBuffer.getChannelData(0)[i]);
                }
                // Fingerprint using DynamicsCompressor (sum of buffer values):
                shortPrint = pxi_output.toString();

                pxi_compressor.disconnect();

                resolve(`${useFullPrint ? fullPrint : shortPrint}`);
            };
        } catch (err) {
            console.error(err);
            resolve('');
        }
    });
};

补充:

实际开发中, 发现 fingerprintjs 库也用的相似的参数值, 项目的src/sources/audio.ts 中使用的数值与本方法中的数据基本相同,

之后如果要获取其他数据生成指纹, 可参考此项目的 src/source/index.ts , 其顶部引入了很多获取设备信息的方法, 想要啥信息直接去引入文件找

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值