标点符(钱魏 Way)

如何设置一个永远无法删除的Cookie

在网站统计中,我们最常用的是用 Cookie标识身份,由于浏览器自带的 Cookie容易被用户删除。于是很多人使用 Flash Cookie来跟踪用户的信息。但是在目前360等软件帮助下,删除Flash Cookie也变得非常的简单。那么有没有什么方法让Cookie无法删除呢?答案是有的!做开发的基本上都理解灾备机制。即一台服务器如果出现了故障,则可由由另一台恢复回去。比如Cookie一旦删除后,这可通过Flash Cookies进行恢复。另外,除了Cookie和Flash Cookie外,到底还有哪些方式可以用来进行“用户识别”。

1、标准的 Http Cookie

HTTP Cookie是最常的用于“用户识别”的方式,以下为服务器与Cookie之间的交互流程:

  1. 当我们用浏览器访问一个网站的时候,就会想服务器发起一个请求。
  2. 根据请求的url和cookie本身的属性,筛选出需要发送给服务器的cookie(当然也有可能没有cookie)。
  3. 如果有多个cookie的话,还会决定发送的顺序。
  4. 把这些需要发送的cookie包含在HTTP的包头里发送给服务器。
  5. 然后到了应答阶段,服务器会发回一个应答包头,包头里包含了cookie信息。
  6. 浏览器解析这个cookie,包括名称,值,路径等元素。
  7. 最后,把cookie保存在本地。

至于哪些cookie会被发送到服务器端,是有一套规则的,例如域名选择、路径选择和Max-Age选择,这些都可以在RFC2109里找到。

每次的http请求,cookie都会包含在包头里发送给服务器,这也是被开发者广为诟病的一个cookie缺点,因为这意味这每个请求都无形中增加了流量,特别是像请求图片这些资源的时候,附带的cookie信息是完全没有必要的。所以现在很多网站图片等静态资源都会用独立的域名运作,这样就可以单独对这些域名进行cookie设置。 除此以外,cookie还有以下影响比较大的缺点:

  • 安全性问题。cookie在http请求中是明文传递的,除非使用SSL通道,不然是不宜在cookie里放置重要信息。
  • 大小问题。每个cookie的大小不能超过4K。每个Domain下cookie个数根据浏览器不同也不同。

关于Cookies的一些限制问题,可以参考下Nicholas的一篇文章: 浏览器允许的每个域名下的Cookie数:

  • IE7跟IE8限制为50个。
  • Firefox限制为50个。
  • Opera限制30个
  • Safari/WebKit没有限制,但是如果header的大小超过服务器能处理的情况下,则会出现错误。

那如果Cookie数设置超过限制的时候,各浏览器又是如何处理呢:

  • Safari由于没有Cookie数的限制,所以不作讨论。
  • 在IE和Opera下,将会采用LRU(The Least Recently Used)方法,自动踢掉最老的cookie以腾出空间给新的cookie。IE和Opera使用这个方法。
  • Firefox就比较独特:它貌似会随机决定哪些cookie将会保留,尽管最后设置的cookie会被保留。所以在Firefox里不要超过cookie数的限制。

cookie的总大小在各浏览器中也是不同的:

  • Firefox和Safari允许cookie多达4097个字节,其中4096个字节是名字和值,1个字节是=号。
  • Opera允许cookie多达4096个字节,这些字节包含名字、值和=号。
  • IE允许4095个字节,这些字节包含名字、值和=号。

注意这里用的字节,也就是,如果是多字节字符,自然就会占用两个字节。在所有浏览器里,如果设置的cookie大小超过限制,那么它就会被忽略或者不被设置。

从上面,我们可以看到,Cookie确实存在一些不足,但是它的一些缺点也正是它的优点,例如每个请求都会被放到包头里发送给服务器,正是这个特性我们才能很方便的传输sessionid。Cookie的出现可谓大大推动了网页的发展,而且在未来很长的一段时间里,Cookie还会继续发挥它的作用。但是也正是由于Cookie存在种种的不足,才会有新的本地存储技术出现的需求。

2、Local Shared Objects (Flash Cookies)

Local Shared Objects 即本地共享对象,长被称为Flash Cookie。Flash Cookies是由Adobe公司开发的一个技术,该技术允许Flash对象在每个域名上存储100KB的数据。LSO解决了Cookie的一些问题,例如大小,安全等。跟Cookie不同,LSO被保存为二进制文件(不过变量名具有可读性)。LSO具有了不少优点,但是缺点也是明显,就是它需要安装Flash这个插件。虽然现在Flash的普及率很高,但是这种依赖插件的技术始终不能解决问题的根源,而且为了使用这个方案不得不引入额外的swf和js文件。另外IE8开始和Chrome在删除历史记录的时候会将Flash Cookie删除掉。

3、Silverlight Isolated Storage

独立存储(Isolated Storage)是Silverlight 2中提供的一个客户端安全的存储,它是一个与Cookie机制类似的局部信任机制。独立存储机制的APIs 提供了一个虚拟的文件系统和可以访问这个虚拟文件系统的数据流对象。Silverlight中的独立存储是基于 .NET Framework中的独立存储来建立的,所以它仅仅是.NET Framework中独立存储的一个子集。

Silverlight中的独立存储有以下一些特征:

  1. 每个基于Silverlight的应用程序都被分配了属于它自己的一部分存储空间, 但是应用程序中的程序集却是在存储空间中共享的。一个应用程序被服务器赋给了一个唯一的固定的标识值。基于Silverlight的应用程序的虚拟文件系统现在就以一个标识值的方式来访问了。这个标识值必须是一个常量,这样每次应用程序运行时才可以找到这个共享的位置。
  2. 独立存储的APIs 其实和其它的文件操作APIs类似,比如 File 和 Directory 这些用来访问和维护文件或文件夹的类。 它们都是基于FileStream APIs 来维护文件的内容的。
  3. 独立存储严格的限制了应用程序可以存储的数据的大小,目前的上限是每个应用程序为1 MB。

4、IE浏览器 userData 存储   (从IE9开始, 不再支持 userData)

userData是微软在第一次浏览器大战中的产物,属于DHTML中的一种技术。相比起Cookie,userData在每个域名下可存储达的数据提升了不少,但是具体的大小视domain的安全域而定。userData的数据会一直存在,直到被删除或者到过期时间。并且基于安全的考虑,一个 userData 存储区只能用于同一目录和对同一协议进行存储。userData在数据的本地储存来说,比cookie进步了不少,但是它有个致命的缺点:仅支持IE。仅凭这一点,就注定了userData并不会有太大的作为,只能用作配合其他本地存储技术兼容低版本的IE。

5、利用 HTTP ETags 存储Cookie

Etag 是URL的Entity Tag,用于标示URL对象是否改变,区分不同语言和Session等等。具体内部含义是使服务器控制的,就像Cookie那样。

HTTP协议规格说明定义ETag为“被请求变量的实体值” 。另一种说法是,ETag是一个可以与Web资源关联的记号(token)。典型的Web资源可以一个Web页,但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端。

6、在浏览器历史记录中存储cookie

大家都知道,用户访问过一次页面,就会存储在浏览器浏览历史里面,这个方法就是利用浏览器的这个特性。通过新建一个iframe去访问这个页面。如默认的url是http://www.example.com/test/。

那他发送的路径会是加上了name跟value的。这里的name跟value分别是id跟123456,如

http://www.example.com/test/id/123456

发送方法为每个字母递增发送,并在最后加个”-“的结束符号

http://www.example.com/test/i

http://www.example.com/test/id

http://www.example.com/test/id/123456

http://www.example.com/test/id/123456-

那要相应的name value他是这样获取的。

默认url加上 ”ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=-“。其中一个字符,看看是否存在历史记录里面。不存在则循环查找下一个。如果这里查到i是访问过的 ,则继续循环,在i的后面循环检查。继而又查到d是访问过的。一直循环知道出现’-‘符号为止。继而解析获取到的字符串,那name value自然也就解析出来。

但这样做的弊端很大。首先,必须要连续发送n个url,用户体验不好。获取的时候要遍历,也影响了浏览器的性能。所以不推荐。

7、使用PNG像素图片保存Cookie

以自动生成、强制缓存的PNG像素图片的RGB值形式保存cookie,使用HTML5 Canvas标签读取像素图片(cookie)。

服务器创建一个宽100像素高1像素的黑色空白PNG(每个像素的RGB 颜色可存储3个字节,可存储600字节信息),然后将值拆分并按顺序每3个字母生成一个RGB颜色值并且按顺序设置到图片的像素点中,然后给这个图片设置一个expires非常长的时间(Expire 头,用于客户端缓存,不同于cookie的expire属性)读取的时候取出并且解析还原出来。要求浏览器必须支持html5才能用上此方法。ie8,ie9,ff,chrome,safari都是 ok的。

8、使用window.name储存Cookie

window.name 传输技术,原本是 Thomas Frank 用于解决 cookie 的一些劣势(每个域名 4 x 20 Kb 的限制、数据只能是字符串、设置和获取 cookie 语法的复杂等等)而发明的(详细见原文:《Session variables without cookies》),后来 Kris Zyp 在此方法的基础上强化了 window.name 传输 ,并引入到了 Dojo dojox.io.windowName),用来解决跨域数据传输问题。

window.name 的美妙之处:name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

name 在浏览器环境中是一个全局/window对象的属性,且当在 frame 中加载新页面时,name 的属性值依旧保持不变。通过在 iframe 中加载一个资源,该目标页面将设置 frame 的 name 属性。此 name 属性值可被获取到,以访问 Web 服务发送的信息。但 name 属性仅对相同域名的 frame 可访问。这意味着为了访问 name 属性,当远程 Web 服务页面被加载后,必须导航 frame 回到原始域。同源策略依旧防止其他 frame 访问 name 属性。一旦 name 属性获得,销毁 frame 。

在最顶层,name 属性是不安全的,对于所有后续页面,设置在 name 属性中的任何信息都是可获得的。然而 windowName 模块总是在一个 iframe 中加载资源,并且一旦获取到数据,或者当你在最顶层浏览了一个新页面,这个 iframe 将被销毁,所以其他页面永远访问不到 window.name 属性。

window.name 传输技术相比其他的跨域传输的一些优势:

  1. 它是安全的。也就是说,它和其他的基于安全传输的 frame 一样安全,例如 Fragment Identifier messaging (FIM)和 Subspace。(I)Frames 也有他们自己的安全问题,由于 frame 可以改变其他 frame 的 location,但是这个是非常不同的安全溢出,通常不太严重。
  2. 它比 FIM 更快,因为它不用处理小数据包大小的 Fragment Identifier ,并且它不会有更多的 IE 上的“机关枪”声音效果。它也比 Subspace 快,Subspace 需要加载两个 Iframe 和两个本地的 HTML 文件来处理一个请求。window.name 仅需要一个 Iframe 和一个本地文件。
  3. 它比 FIM 和 Subspace 更简单和安全。FIM 稍微复杂,而 Subspace 非常复杂。Subspace 也有一些额外的限制和安装要求,如预先声明所有的目标主机和拥有针对若干不同特殊主机的 DNS 入口。window.name 非常简单和容易使用。
  4. 它不需要任何插件(比如 Flash)或者替代技术(例如 Java)。

9、使用HTML5客户端储存数据方法。

HTML5 提供了四种在客户端存储数据的新方法,即

  • HTML5 Session Storage
  • HTML5 Local Storage
  • HTML5 Global Storage
  • HTML5 Database Storage via SQLite

HTML5 Session Storage顾名思义它就如同Session。 针对一个 session 的数据存储,任何一个页面存储的信息在窗口中同一网站的任何页面都可以访问它存储的数据。每个窗口的值都是独立的,它的数据会因窗口的关闭而丢失,不同窗口间的sessionStorage是不可以共享的。

HTML5 Local Storage 没有时间限制的数据存储,第二天、第二周或下一年之后,数据依然可用。也就是说,localStorage是永远不会过期的,除非主动删除数据。数据可跨越多个窗口,无视当前会话,被共同访问、使用。

HTML5 Global Storage 同HTML5 Session Storage一样,区别在于其在浏览器关闭后,可以将存储的信息仍能够保留下来。目前只有FireFox支持,且只支持当前域下的存储。

HTML5 Database Storage via SQLite (目前只谷歌浏览器支持):可以理解成一个Html5环境下可以用Js执行CRUD的Web数据库。对于简单的数据,使用sessionStorage和localStorage能够很好地完成存取,但是对于处理复杂的关系型数据,它就力不从心了。这也是 HTML 5 的“Web SQL Database”API 接口的应用所在。

evercookie

一些常见的用来标注用户身份的方法已经介绍过了,接下来要讲解的是如何使用。Evercookie是一个JavaScript API,通过它可以在浏览器中生成极其持久的cookie。它的目标就是在用户删除了传统cookie、Flash cookie(LSO)和其他缓存数据后,仍然可以识别客户端。Evercookie是通过利用浏览器不同的存储机制,把cookie数据保存在多个不同的地方实现的。此外,如果发现用户删除了其中一些cookie,Evercookie会利用这些机制重新创建它们。

虽然Evercookie非常的强大,但是个人觉得大部分功能都比较花俏。如evercookie_png,evercookie_etag,evercookie_history,实际上这些操作均会对用户体验有一定影响。不过也体现了evercookie的宗旨:为了记录用户信息,无所不用其极。但针对于国内用户大部分为ie用户,而且很多网站是ie only,完全可把evercookie_userdata纳入考虑范围。同时一般情况下,装有silverlight插件的浏览器,几乎必然也装着flash插件。所以首选flash方案。

Evercookie被认为是一项很邪恶的技术,事实上作者Kamkar的座右铭是“think bad, do good”。Kamkar说,他写evercookie是为了向用户展示公司可以跟踪他们的方法。

“我希望evercookie只是向人们演示跟踪他们的是何种方法,由他们决定他们是否应该阻止这些方法,我作为一个安全业余爱好者,写evercookie也才用了不到一天的时间,因此我很容易想像那些受雇的开发者可以做出什么来。”

有证据表明,Hulu、AOL和Spotify等网站已经开始在自己的网站上使用EverCookies。

参考链接:

http://en.wikipedia.org/wiki/HTTP_cookie

http://en.wikipedia.org/wiki/Zombie_cookie

http://samy.pl/evercookie/

https://github.com/samyk/evercookie

码字很辛苦,转载请注明来自标点符《如何设置一个永远无法删除的Cookie》

评论

  1. justjavac #1

    虽然有点儿长,但是解释的很透彻。

    回复
    2013-05-8
    • thankwsx

      怎么哪都有你,这个是不是翻译的哦?没有说明每种方法的跨浏览器属性。比如Flash LSO是跨浏览器的。

      回复
      2013-06-19
      • 标点符

        不是翻译的,参考一些资料自己整理的

        回复
        2013-06-25