cookie僵尸——evercookie分析(三)【转】
这篇文章来对evercookie的js源码进行分解下,
因为源码太长,这里发2个个人觉得最有意思的方法出来,顺便做了点小解释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
BwStore.evercookie_history = function (name, value) { // - is special var baseStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=-" ; var baseElems = baseStr.split( "" ); // sorry google. if ( typeof (value) != "undefined" ) { // don't reset this if we already have it set once // too much data and you can't clear previous values if ( this .hasVisited(url)) return ; this .createIframe(url, 'if' ); url = url + '/' ; var base = this .encode(value).split( "" ); for ( var i = 0; i < base.length; i++) { url = url + base[i]; this .createIframe(url, 'if' + i); } // - signifies the end of our data url = url + '-' ; this .createIframe(url, 'if_' ); } else { // omg you got csspwn3d if ( this .hasVisited(url)) { url = url + '/' ; var letter = "" ; var val = "" ; var found = 1; while (letter != '-' && found == 1) { found = 0; for ( var i = 0; i < baseElems.length; i++) { if ( this .hasVisited(url + baseElems[i])) { letter = baseElems[i]; if (letter != '-' ) val = val + letter; url = url + letter; found = 1; break ; } } } // lolz return this .decode(val); } } } |
这个方法算是evercookie最经典的一个方法了
大家都知道,用户访问过一次页面,就会存储在浏览器浏览历史里面,这个方法就是利用浏览器的这个特性。通过新建一个iframe去访问这个页面。
如默认的url是http://www.google.com/evercookie/cache/
那他发送的路径会是加上了name跟value的。这里的name跟value分别是id跟onedear,如
http://www.google.com/evercookie/cache/id/onedear
发送方法为每个字母递增发送,并在最后加个”-“的结束符号
http://www.google.com/evercookie/cache/i
http://www.google.com/evercookie/cache/id
。。。。
http://www.google.com/evercookie/cache/id/onedea
http://www.google.com/evercookie/cache/id/onedear
http://www.google.com/evercookie/cache/id/onedear-
那要相应的name value他是这样获取的。
默认url加上”ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=-“。其中一个字符,看看是否存在历史记录里面。不存在则循环查找下一个。如果这里查到i是访问过的。http://www.google.com/evercookie/cache/i ,则继续循环,在i的后面循环检查。继而又查到d是访问过的。http://www.google.com/evercookie/cache/id,一直循环知道出现’-‘符号为止。继而解析获取到的字符串,那name value自然也就解析出来。
但这样做的弊端很大。首先,必须要连续发送n个url,用户体验不好。获取的时候要遍历,也影响了浏览器的性能。
所以不推荐。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
BwStore.evercookie_png = function (name, value) { //alert(document.createElement('canvas').getContext); if (document.createElement( 'canvas' ).getContext) { if ( typeof (value) != "undefined" ) { // make sure we have evercookie session defined first document.cookie = 'evercookie_png=' + value; // evercookie_png.php handles the hard part of generating the image // based off of the http cookie and returning it cached var img = new Image(); img.style.visibility = 'hidden' ; img.style.position = 'absolute' ; img.src = 'evercookie_png.php?name=' + name; } else { _ec.pngData = undefined; var context = document.createElement( 'canvas' ); context.style.visibility = 'hidden' ; context.style.position = 'absolute' ; context.width = 200; context.height = 1; var ctx = context.getContext( '2d' ); // interestingly enough, we want to erase our evercookie // http cookie so the php will force a cached response var origvalue = this .getFromStr( 'evercookie_png' , document.cookie); document.cookie = 'evercookie_png=; expires=Mon, 20 Sep 2010 00:00:00 UTC; path=/' ; var img = new Image(); img.style.visibility = 'hidden' ; img.style.position = 'absolute' ; img.src = 'evercookie_png.php?name=' + name; img.onload = function () { // put our cookie back document.cookie = 'evercookie_png=' + origvalue + '; expires=Tue, 31 Dec 2030 00:00:00 UTC; path=/' ; _ec.pngData = '' ; ctx.drawImage(img,0,0); // get CanvasPixelArray from given coordinates and dimensions var imgd = ctx.getImageData(0, 0, 200, 1); var pix = imgd.data; // loop over each pixel to get the "RGB" values (ignore alpha) for ( var i = 0, n = pix.length; i < n; i += 4) { if (pix[i ] == 0) break ; _ec.pngData += String.fromCharCode(pix[i]); if (pix[i+1] == 0) break ; _ec.pngData += String.fromCharCode(pix[i+1]); if (pix[i+2] == 0) break ; _ec.pngData += String.fromCharCode(pix[i+2]); } } return _ec.pngData; } } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$x = 200; $y = 1; $gd = imagecreatetruecolor( $x , $y ); $data_arr = str_split ( $_COOKIE [ "evercookie_png" ]); $x = 0; $y = 0; for ( $i = 0; $i < count ( $data_arr ); $i += 3) { $color = imagecolorallocate( $gd , ord( $data_arr [ $i ]), ord( $data_arr [ $i +1]), ord( $data_arr [ $i +2])); imagesetpixel( $gd , $x ++, $y , $color ); } Ever_cookie_png.php |
服务器创建一个宽100像素高1像素的黑色空白PNG(每个像素的RGB 颜色可存储3个字节,可存储600字节信息),然后将值拆分并按顺序每3个字母生成一个RGB颜色值并且按顺序设置到图片的像素点中,读取的时候取出并且解析还原出来。还原需要用到'canvas'标签,要求浏览器必须支持html5才能用上此方法。ie8,ie9,ff,chrome,safari都是ok的