引言:javascript
前端持久化就是要将数据永久的保存在前端,让数据难以删除或者删除后可以从新恢复。存储的数据能够理解为是一种 “僵尸数据”,下面介绍一种前端持久化方法 -- evercookie。php
一.evercookie简介:html
evercookie是由Samy Kamkar(美国白帽黑客、安全研究员)开发的一组jsApi,它的目的在于持久化cookie,即便用户清除标准cookie、Flash cookie等以后依然可以获取设置过的数据,而且从新恢复清除掉的cookie(比较狭隘,本质上是恢复全部维度,一个从新写的动做)。前端
二.evercookie原理:java
evercookie的原理很简单,就是将数据写入浏览器各个维度,获取的时候再从各个维度中读出来,不管用户怎样清洗,只要其中一个维度有数据就能够获得数据。比较强大的地方在于:1.存储的维度很是多,用户很难清理;2.取数据的时候会将已经清除的数据从新恢复,名副其实的僵尸cookie。web
下面介绍下存储的维度以及读取数据的方式和思路:chrome
evercookie 存储数据的维度:数据库
1.标准HTTP Cookie:canvas
evercookie会将数据存在 document.cookie 中,获取的时候直接获取就能够了,没什么可说的,这部分数据是比较容易被清除的,好比浏览器清除cookie、js脚本设置等,分享关于cookie的两个点:跨域
2.Flash Cookie:
evercookie提供了一个flash文件,使用的时候会将数据存储在flash的本地对象中,只有删除对应的flash存储文件才能够清除,把flash文件反编译了一下,获得了AS源码:
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源码:
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,对js来讲就是读取flash数据。
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.localStorage: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.图片缓存数据存储:
evercookie利用了图片的缓存进行了存储,简单介绍下:
这里面能够看出两点,一个 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插件。evercookie提供了相应的编译文件能够经过sliverlight进行存取数据,对sliverlighr不大了解,有兴趣的同窗能够研究一下。
12.java应用程序本地存储:经过使用JNLP调用Java Applet的能力将数据存在了本地文件中,代码量比较大不细分析了,反编译了jar包以及class文件,放在文件中有兴趣的能够看下。
13.IE的userData存储:
userData是IE独有的一种存储方式,能够经过XML、HTML标签将数据存储在本地,通常支持IE5以上,官方文档看存储数据大小通常在单个域名640k左右,使用方法很简单
<!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("devinn", 1990); window.console && console.log(get("devinn"));//1990 </script> </html>
14.window.name:
window.name是window的一个很特殊的属性,能够设置,有两个特色:
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便可获取;
跨域获取注意两个关键点:
15.<a>标签历史访问状态存储:
浏览器中的 <a> 标签有个特性, 同一个浏览器被访问事后状态会变成 "visited" 状态,通常只有清理浏览器浏览记录才会消失,evercookie利用了这点进行存储。
简单说下思路:
说明:2中设置的值是个encode后的值,最后一步解出的字符拼装后须要decode后才能获取到原来的值,evercookie里面的实现颇有意思,有兴趣的能够看下。
16.HSTS存储:
HSTS通常用来防止中间人攻击, 简单来讲,若是一个域名的http响应设置过 Strict-Transport-Security,那么此域名再次发送http请求时浏览器会直接转成https请求(能够设置prelist,第一次请求也能够直接在浏览器端转成https),利用这点能够作数据存储:
直接看实现:
<?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。
evercookie读数据:
evercookie读数据只说一点就能够了,它的思想并非从任意维度获取到数据就直接返回结果,而是要将全部设置的维度所有取出进行最优解查找,能够防止部分数据被篡改致使的数据异常;也带来一个问题,由于不少都是异步获取,好比数据库、e-tag等,那么获取数据就不是当即获取,会有一部分等待时长。
三.应用:
使用evercookie进行持久化,可让咱们的数据常驻浏览器。利用它不只能够收集各类浏览器数据,更重要的是,即便用户对浏览器cookie进行了大清洗,这些数据仍然能够起死回生。好比,利用它能够给浏览器创建一个长期有效的身份标识符,利用标识符上报数据对用户的历史信息进行分析进而判断一个操做是善意仍是恶意, 对前端风控体系有很大做用。
四.总结:
evercookie简单来说就是存数据取数据,并无多少东西,比较闪光的地方在于里面的存取数据的维度和方法,各类奇淫巧技。同时要注意到里面的一些方法,好比HSTS会带来很大开销,获取数据是一个异步过程也会有时间开销,应用的时候尽可能根据业务额场景来调整使用。