前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >鹅厂原创 | 前端持久化 -- evercookie

鹅厂原创 | 前端持久化 -- evercookie

作者头像
用户1097444
发布2022-06-29 15:41:08
9780
发布2022-06-29 15:41:08
举报
文章被收录于专栏:腾讯IMWeb前端团队

戳蓝字“IMWeb前端社区”关注我们哦!

文/devinnzhang

腾讯TEG事业群——前端开发 工程师

0写在前面

前端持久化就是要将数据永久的保存在前端,让数据难以删除或者删除后能够重新恢复。存储的数据可以理解为是一种 “僵尸数据”,下面介绍一种前端持久化方法 -- evercookie。

(左右滑动查看代码)

1evercookie简介

evercookie是由Samy Kamkar(美国白帽黑客、安全研究员)开发的一组jsApi,它的目的在于持久化cookie,即使用户清除标准cookie、Flash cookie等之后依然能够获取设置过的数据,并且重新恢复清除掉的cookie(比较狭隘,本质上是恢复所有维度,一个重新写的动作)。

2evercookie原理

2.1 evercookie的原理

就是将数据写入浏览器各个维度,获取的时候再从各个维度中读出来,只要其中一个有数据就可以将数据取出。比较强大的地方在于:1.存储的维度非常多,寻常用户难以清理;2.取数据的时候会将清除的数据重新恢复,名副其实的僵尸cookie;下面介绍下存储的维度以及读取数据的方式和思路。

2.2 evercookie 存储数据的维度

1) 标准HTTP Cookie

evercookie会将数据存在 document.cookie 中,获取的时候直接获取就可以了,没什么可说的,这部分数据是比较容易被清除的,比如浏览器清除cookie、js脚本设置等,分享关于cookie的两个点:

  • http请求自带本域以及根域下所有cookie,CSRF的根源就在这里;
  • js设置cookie默认在当前域以及当前路径下, cookie一般都会跨路径使用,一定注意设置path字段;

2) Flash Cookie

evercookie提供了一个flash文件,使用的时候会将数据存储在flash的本地对象中,只有删除对应的flash存储文件才可以清除,把flash文件反编译了一下,可以看到AS的源码:

代码语言:javascript
复制
shared = sharedobject.getlocal("evercookie");if (everdata) {    var newdata = everdata.split("=");    var str = shared.data.cookie;    var results = str.split("&");    var i = 0;    while (i < results.length) {        var elem = results[i].split("=");        if (elem[0] != newdata[0]) {
            everdata = everdata + ("&" + results[i]);
        }
        i++;
    }
    shared.data.cookie = everdata.replace("\\", "\\\\");
    shared.flush();
}
flash.external.ExternalInterface.call("_evercookie_flash_var", shared.data.cookie);

存数据的时候调用swfObject中的接口存入即可,可以看下js源码:

代码语言:javascript
复制
this.evercookie_lso = function (name, value) {    var div = document.getElementById("swfcontainer"),
        flashvars = {},
        params = {},
        attributes = {};    if (div===null || div === undefined || !div.length) {
        div = document.createElement("div");
        div.setAttribute("id", "swfcontainer");        document.body.appendChild(div);
    }    if (value !== undefined) {
        flashvars.everdata = name + "=" + value;
    }
    params.swliveconnect = "true";
    attributes.id        = "myswf";
    attributes.name      = "myswf";    //写入flash
    swfobject.embedSWF(_ec_baseurl + _ec_asseturi + _ec_swf_file_name, "swfcontainer", "1", "1", "9.0.0", false, flashvars, params, attributes);
};

flash加载后会使用 flash.external.ExternalInterface.call("_evercookie_flash_var", shared.data.cookie) 调用window下的javascript方法 _evercookie_flash_var 将数据传给js,就是读取flash数据。

代码语言:javascript
复制
var _global_lso;function _evercookie_flash_var(cookie) {
    _global_lso = cookie;    // remove the flash object now
    var swf = document.getElementById("myswf");    if (swf && swf.parentNode) {
        swf.parentNode.removeChild(swf);
    }
}window._evercookie_flash_var = _evercookie_flash_var;

3) ocalStorage

localStorage是HTML5的一个新特性,可以将数据永久存储在本地,获取时没有窗口的限制,同域下即可获取,可以调用localStorage的接口来清除,浏览器直接清除缓存数据也能清掉;

4) sessionStorage

同localStorage类似,生存周期是当前对话,浏览器关闭重新打开后消失;

5) globalStorage

同localStorage类似,同样是永久存储在本地,目前只有 Firefox48 以上才支持;

6) openDatabase

HTML5的WebSQL数据库,可以理解为本地存储 Local Storage 和 Session Storage 的一个加强,用来操纵大量结构化数据,由于各个浏览器实现原因,WebSQL规范已经被废弃掉了;

7) IndexedDB

浏览器内置的一种数据库,永久保存数据,IndexDB与WebSQL比较,IndexedDB更像是一个NoSQL数据库,而WebSQL更像是关系型数据库,使用SQL查询数据;

8) IndexedDB

evercookie利用了图片的缓存进行了存储,简单介绍下:

  • 写数据的时候根据key构造一个http请求,将值通过document.cookie传给后台;
  • 后台根据cookie中传入的值按照每三位生成一个像素点的方式生成一张png图片(evercookie设置了200个像素点),并且设置缓存到前端;
  • 读数据的时候同样根据key构造相同的http请求,获取缓存的图片并用canvas解析出对应的像素点,恢复出数据。

这里面可以看出两点,一个 evercookiejs 设置的图片存储支持的最大数据为600个字符,二是此种方式必须使用canvas进行解析,有兼容性要求,这种方式可以通过浏览器清除缓存直接清掉;

9) ETag存储

ETag存储也要依靠后台,利用的原理主要是当浏览器第一次访问一个请求的时候如果服务器响应设置ETag标签,浏览器第二次访问会自动带上一个IF-NONE-MATCH上来(跟ETag设置的值相同),所以只要把数据值存在ETag上,取数据的时候直接去后台查链接上的 IF-NONE-MATCH 字段就可以了, 跟上面png图片缓存类似。

10) web Cache

看evercookie的思路是对 http cookie 的一种加强,相当于通过后台对cookie设置个过期时间,evercookie提供的脚本感觉有问题。

11) silvelright客户端存储

silvelright也是一种本地存储方式,可以将数据直接存在本地,类似于flash可以跨浏览器获取,需要安装silverlight插件、下载 .xap 的编译文件,对sliverlight不了解,有兴趣的同学可以自行研究一下。

12) java应用程序本地存储

通过使用JNLP调用Java Applet的能力将数据存在了本地文件中,代码量比较大不细分析了,反编译了jar包以及class文件,放在附件里有兴趣的可以看下。

13) IE的userData存储

userData是IE特有的一种存储方式,可以通过XML、HTML标签将数据存储在本地,一般支持IE5以上,官方文档单个域名存储数据大小一般在640k左右,使用方法很简单

代码语言:javascript
复制
<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <style>
        .userData{            behavior: url(#default#userdata)
        }    </style></head><body>
    <div id="userData" class="userData"></div></body><script>
    var persistDom = document.getElementById("userData");    function set(name, value){
        persistDom.setAttribute(name, value);
        persistDom.save(name);
    }     function get(name){
        persistDom.load(name);        return persistDom.getAttribute(name)
    }
    set("userdata", "devinn");    window.console && console.log(get("userdata"));// devinn</script></html>

14) window.name

window.name是window的一个很特殊的属性,可以设置,有两个特点:

  • window.name设置后刷新页面不会消失;
  • iframe从一个src跳转到另一个src 获取contentWindow.name 不会发生变化;

evercookie主要是利用了上面的一点,只要页面不刷新,页面随便清理都不会发生变化(奇特的是放在iframe里面清缓存就可以清掉 TT)。

window.name经常用于跨域通信,顺便说下window.name跨域通信原理:

iframe src 从 A.html跳转到 B.html 的时候 window.name 是不变的, 所以如果一个域的页面想跨域获取数据可以设置一个iframe 先将src指向想要获取数据的域页面(此页面将想要传递的数据放在window.name中, ps:此时由于跨域无法获取iframe的contentWindow),之后src指向自己域名下的一个页面(已变成同域)通过iframe的contentWindow即可获取;  

跨域获取注意两个关键点:

  • 必须放在iframe中;
  • 必须使用name属性(console了一下contentWindow,测试了几个其他属性都不行);

15) <a>标签历史访问状态存储

浏览器中的 <a> 标签有个特性, 同一个浏览器被访问过后状态会变成 "visited" 状态,一般只有清理浏览器浏览记录才会消失,evercookie利用了这点进行存储。

简单说下思路:

  1. 构造<a>标签并预设visited样式(a:visited)作为访问校验值;
  2. 构造http请求,请求的地址为设置的键以及值的各个字符(多个http,个数是值的长度);
  3. 写数据通过构造iframe对上面的http请求进行一次访问;
  4. 读数据用键和一个字符构造一个链接赋予<a>标签的href,获取<a>标签的样式与预设visited样式进行
  5. 直接将http请求赋给<a>标签的href,获取如果样式为预设visited的样式说明这个http请求访问过,解出字符;

说明:

2中设置的值是个encode后的值,最后一步解出的字符拼装后需要decode后才能获取到原来的值,evercookie里面的实现很有意思,有兴趣的可以看下。

16) HSTS存储

HSTS一般用来防止中间人攻击, 简单来说,如果一个域名的http响应设置过 Strict-Transport-Security,那么此域名再次发送http请求时浏览器会直接转成https请求(可以设置prelist,第一次请求也可以直接在浏览器端转成https)

利用这点可以做数据存储:

  1. 申请多个域名(例如32个),构造好服务,设置(端口注意设置成443或者80)、清除、查询;
  2. 将设置的值转为二进制整数,比如 1101, 1的bit发送到对应的第一个域名设置 Strict-Transport-Security,0的清除掉 Strict-Transport-Security: max-age=0;
  3. 获取时向上面32个域名发送请求进行查询,服务器返回是否是http,对应的bit位设置为0,对应的二进制转成数值就是获取的结果;

直接看实现:

代码语言:javascript
复制
<?php//header('Access-Control-Allow-Origin: *');$is_ssl = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443;if(isset($_GET['SET'])){    if($is_ssl){
        header('Strict-Transport-Security: max-age=31536000');
        header('Content-type: image/png');        echo base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAgAAAAJCAIAAACAMfp5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYSURBVBhXY/z//z8DNsAEpTHAkJJgYAAAo0sDD8axyJQAAAAASUVORK5CYII=');
    }else{
        $redirect = "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
        header("Location: $redirect");
    }    die();
}if(isset($_GET['DEL'])){    if($is_ssl){
        header('Strict-Transport-Security: max-age=0');
    }else{
        $redirect = "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
        header("Location: $redirect");
    }    die();
}if($is_ssl){
    header('Content-type: image/png');    // some white pixel
    echo base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAgAAAAJCAIAAACAMfp5AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYSURBVBhXY/z//z8DNsAEpTHAkJJgYAAAo0sDD8axyJQAAAAASUVORK5CYII=');    die();
}else{
    header('X-PHP-Response-Code: 404', true, 404);
}?>

HSTS存储方式缺点比较大,要申请多个域名,发送多个请求,evercookie默认关闭了HSTS存储,chrome和firefox兼容性比较好、IE不支持HSTS设置, 浏览器也可以手动设置关闭HSTS.

2.3 evercookie读数据:

evercookie读数据只说一点就可以了,它的思想并不是从任意维度获取到数据就直接返回结果,而是要将所有设置的维度全部取出进行最优解查找,可以防止部分数据被篡改导致的数据异常;也带来一个问题,因为很多都是异步获取,比如数据库、e-tag等,那么获取数据就不是立即获取,会有一部分等待时长。

3应用

使用evercookie进行持久化,可以让我们的数据常驻浏览器,利用它不仅可以收集各种浏览器数据,更重要的是,即使用户对浏览器cookie进行了大清洗,这些数据仍然可以起死回生。比如,利用它可以给浏览器建立一个长期有效的身份标识符,利用标识符上报数据对用户的历史信息进行分析进而判断一个操作是善意还是恶意, 对前端风控体系有很大作用。

4总结

evercookie简单来讲就是存数据取数据,并没有多少东西,比较闪光的地方在于里面的存取数据的维度和方法,各种奇淫巧技。

同时要注意到里面的一些方法,比如HSTS会带来很大开销,获取数据是一个异步过程也会有时间开销,应用的时候尽量根据业务额场景来调整使用。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯IMWeb前端团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0写在前面
  • 1evercookie简介
  • 2evercookie原理
  • 3应用
  • 4总结
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档