canvas指纹在safari浏览器下不稳定,初次加载刷新后会变

问题描述

最近在研究设备指纹,看到现下比较靠谱的是canvas指纹,能够忽略无痕模式的影响,保证浏览器指纹的稳定性,于是想尝试一下。但是尝试了一下发现chrome,IE10,Edge,Firefox,Opera在正常模式和无痕模式下,设备指纹都是一致的,唯独safari有点不同,无痕模式下不管怎么刷新,指纹D都是保持不变,而在正常模式下,有一定概率第一次生成的指纹A和刷新页面后第二次生成的B不一致,同时再次反复刷新,生成的指纹CB/D是始终保持一致的。

我就很费解了同一台设备,同一个浏览器,同样的canvas图和操作为什么会有这样刷新页面就会变的操作。检查了一下输出后发现,在safari用canvas.toDataURL()生成的canvas的base64字符串会变。就闹不明白了这是为什么,跪求大佬们指点迷津。。。

问题截图

第一次
image.png
第二次
image.png
可以看到是截取的最后几位dataURL发生了变化所以加密的时候出了问题

测试代码

<!DOCTYPE html>
<html>
    <body>
        <style>
            html {
                font-family: Arail;
            }
        </style>
        <div id="result1"></div>
        <div id="result2"></div>
        <div id="result3"></div>
        <canvas id="drawing" width=" 200" height="200"
            >A drawing of something.</canvas
        >

        <script>
            var canvasFP1 = '';
            var canvasFP2 = '';
            function bin2hex(s) {
                console.log('inner bin2hex', s);
                var i,
                    l,
                    o = '',
                    n;
                s += '';
                for (i = 0, l = s.length; i < l; i++) {
                    n = s.charCodeAt(i).toString(16);
                    o += n.length < 2 ? '0' + n : n;
                }
                return o;
            }
            function hashstr(s) {
                console.log('inner hashstr', s);
                var hash = 0;
                if (s.length == 0) return hash;
                for (i = 0; i < s.length; i++) {
                    // console.log(i, s.charCodeAt(i));
                    char = s.charCodeAt(i);
                    hash = (hash << 5) - hash + char;
                    // console.log(i, hash);
                    hash = hash & hash; // Convert to 32bit integer
                    // console.log(i, 'hash2', hash);
                }
                return hash;
            }
            function FPjs() {
                var result = [];
                // Very simple now, need to make it more complex (geo shapes etc)
                var canvas = document.getElementById('drawing');
                canvas.width = 2000;
                canvas.height = 200;
                canvas.style.display = 'inline';
                var ctx = canvas.getContext('2d');
                // detect browser support of canvas winding
                // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/
                // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js
                ctx.rect(0, 0, 10, 10);
                ctx.rect(2, 2, 6, 6);
                result.push(
                    'canvas winding:' +
                        (ctx.isPointInPath(5, 5, 'evenodd') === false
                            ? 'yes'
                            : 'no'),
                );

                ctx.textBaseline = 'alphabetic';
                ctx.fillStyle = '#f60';
                ctx.fillRect(125, 1, 62, 20);
                ctx.fillStyle = '#069';
                // https://github.com/Valve/fingerprintjs2/issues/66
                ctx.font = '11pt Arial';
                // if (options.dontUseFakeFontInCanvas) {
                //     ctx.font = '11pt Arial';
                // } else {
                //     ctx.font = '11pt no-real-font-123';
                // }
                ctx.fillText(
                    'Cwm fjordbank glyphs vext quiz, \ud83d\ude03',
                    2,
                    15,
                );
                ctx.fillStyle = 'rgba(102, 204, 0, 0.2)';
                ctx.font = '18pt Arial';
                ctx.fillText(
                    'Cwm fjordbank glyphs vext quiz, \ud83d\ude03',
                    4,
                    45,
                );

                // canvas blending
                // http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/
                // http://jsfiddle.net/NDYV8/16/
                ctx.globalCompositeOperation = 'multiply';
                ctx.fillStyle = 'rgb(255,0,255)';
                ctx.beginPath();
                ctx.arc(50, 50, 50, 0, Math.PI * 2, true);
                ctx.closePath();
                ctx.fill();
                ctx.fillStyle = 'rgb(0,255,255)';
                ctx.beginPath();
                ctx.arc(100, 50, 50, 0, Math.PI * 2, true);
                ctx.closePath();
                ctx.fill();
                ctx.fillStyle = 'rgb(255,255,0)';
                ctx.beginPath();
                ctx.arc(75, 100, 50, 0, Math.PI * 2, true);
                ctx.closePath();
                ctx.fill();
                ctx.fillStyle = 'rgb(255,0,255)';
                // canvas winding
                // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/
                // http://jsfiddle.net/NDYV8/19/
                ctx.arc(75, 75, 75, 0, Math.PI * 2, true);
                ctx.arc(75, 75, 25, 0, Math.PI * 2, true);
                ctx.fill('evenodd');

                if (canvas.toDataURL) {
                    result.push(
                        'canvas fp:' + canvas.toDataURL('image/jpeg', 0.5),
                    );
                }
                var tempStr = result[1].slice(-16, -1);
                var result11 = hashstr(tempStr);
                var result22 = hashstr(result.join(','));
                var result1 = document.getElementById('result1');
                result1.innerHTML = 'canvasFP1 is : ' + result11;
                var result2 = document.getElementById('result2');
                result2.innerHTML = 'canvasFP2 is : ' + result22;
                if (localStorage.getItem('result')) {
                    localStorage.setItem('new_result', result[1]);
                    console.log(
                        'is different',
                        localStorage.getItem('result') !== result[1],
                    );
                    console.log(
                        'new length is ',
                        result[1].length,
                        'old length is ',
                        localStorage.getItem('result').length,
                    );
                } else {
                    localStorage.setItem('result', result[1]);
                }
                return result11 + '---' + result22;
            }
            console.log(FPjs());
            
        </script>
    </body>
</html>
阅读 3.6k
1 个回答

忘了结帖,code没错,只是在浏览器层面,不同浏览器会对canvas指纹、webGL指纹、audio指纹添加噪声,实现反追踪,所以我们最后是通过收集其他信息,优化了策略才完成了设备指纹这一产品

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题