Anehta的水印(Watermark)机制
作者:刺
Anehta中采用了一种同机识别的技术,我在项目中将其称为“水印”(Watermark).
看过我的录像演示的人应该有印象,效果如下:
如果一个客户端被打上了水印,那么,不管客户端删除了cookie、缓存,抑或是切换了各种不同的浏览器,其水印都不会变化。
换句话来说,就是常规的清除上网痕迹的措施,都无法清除掉anehta给客户端打上的水印。
这看起来好像跟变魔术一样,其实揭穿了很简单,我是通过Flash的shared objects来做的,也可以称作flash cookie。
其实这种技术在比较早的时候foundstone的paper中就提到过了,同时还有提到的是一个IE persistence Data,会保存在IE临时文件的一个index.dat中,也是光删cookie或缓存删不掉的。但是这个持久数据在IE7中已经不能再这么利用了,所以我这里仅仅使用了flash的cookie。
而yahoo和alibaba都使用了这种技术用在登录入口来防范钓鱼的威胁。
正常来说,flash cookie保存在系统的如下位置:
C:\Documents and Settings\yourusername\Application Data\Macromedia\Flash Player\#SharedObjects\
在这个目录下可以看到非常多的网站目录,里面都有他们的flash留下的痕迹。
由于一般删除cookie、删除缓存等不会来清理这里,所以就给客户端打上了一个水印。 可以看到,这个位置是和windows的系统用户相关的,所以如果切换了一个windows的系统用户,也会导致水印发生改变。
由于flash是跨浏览器的,所以水印也就可以跨浏览器了,显得很神奇:换到了firefox上,还能被认出来!
然而更神奇的是,只要flash的加载位置不变,那么就算从A站切换到了B站,也照样能识别出来。
这是因为flash cookie是记录在flash加载域名下的,所以,如果有如下情景:
www.a.com 上加载了 www.c.com/flash.swf ,打上了一个水印
用户之后访问 www.b.com,这个站上也加载了一个 www.c.com/flash.swf
这时候,用户的水印还是没有变。
也就是说,如果同时针对两个不同域实施了XSS攻击,加载水印后,在不同域能够识别到同一个用户。
这种同机识别技术能够给我们提供很大的便利,Anehta使用它后,能够准确识别到用户,从而进行进一步的统计分析。 这种技术不光在攻击中能用,在实际网站应用中也是非常有用的。
下面看看我是如何在Anehta中实现这一个过程的。
首先需要提到 Flash 的ExternalInterface , 它是在Flash 8中加入的支持,使用之后,就可以和外部的js通信了。具体使用方法请参考手册。
以下是Flash 中的 AS部分
首先,在flash中取shard objects
so = SharedObject.getLocal(“anehtaWatermark”, “/”);
可以把SharedObject理解为一个数组,它的存储是以二进制文件形式存储在本地的,我在这里定义了一个名为 anehtaWatermark 的共享对象,范围是所有子目录。 对应的我的文件名就是 anehtaWatermark.sol ,和上面图片里的一致。
然后需要设定什么域能访问Flash的资源,即设定 allowDomain
System.security.allowDomain(_root.domainAllowed);
这里我是从客户端传回来一个参数,这样就是动态定制了。
然后是比较核心的部分,怎样 读、写 flash cookie:
// 这个是读, 获取so里的名为 watermark的字段的值
function getWatermark(){
ret = “”;
ret = so.data.watermark;
return ret;
}
// 这是写,往名为watermark的字段里写内容
function setWatermark(obj) {
if (!( obj == null)){
so.data.watermark = obj;
}
return so.flush()
}
最后再通过 ExternalInterface添加两个 call back , 和外部的js之间通信
ExternalInterface.addCallback(“setWatermark”, this, setWatermark);
ExternalInterface.addCallback(“getWatermark”, this, getWatermark);
这样,当外部的js 调用这个flash的 setWatermark 和 getWatermark 的函数时,对应的就调用flash内部 AS脚本里的 这两个函数。
flash 完成后,我编译好放在了 /module/flash/anehtaWatermark.swf 里
然后再是js部分,前面说了, Flash 8才有 ExternalInterface, 所以首先要判断浏览器是否支持flash,是否高于版本8. 如果一起都满足了, 就插入flash, 然后写flash cookie,或是读flash cookie。
flash cookie设置好后,最后还是需要传递给cookie,从而让服务器识别。
整个过程逻辑有点复杂,描述如下:
其中与 flash通信的代码如下:
// Using Flash Shared Object to Store Watermark
anehta.core.setWatermark = function(flashID, o){
return document.getElementById(flashID).setWatermark(o);
}
// Get the info from flash
anehta.core.getWatermark = function(flashID){
return document.getElementById(flashID).getWatermark();
}
注意在插入flash的时候,需要设置 flash 的 allowScriptAccess 为always,不然跨域插入flash将访问不到当前域的一些DOM对象
anehta.inject.injectFlash = function(flashId, flashSrc, flashParam) {
//flashParam = ‘?’ + flashParam;
document.write(‘<object type=”application/x-shockwave-flash” data=”‘ + flashSrc +
‘” width=”0″ height=”0″ id=”‘ + flashId +
‘”><param name=”allowScriptAccess” value=”always” /> ‘ +
‘<param name=”movie” value=”‘ + flashSrc + ‘” />’ +
‘<PARAM NAME=FlashVars VALUE=”domainAllowed=’ + flashParam + ‘” />‘ +
‘<param name=”bgColor” value=”#fff” /> </object>’);
}
最后,实现上面那个图里的复杂逻辑过程是在 clx.js 里,代码如下:
// 以下是正常加载clx过程
var ts = new Date();
ts = ts.getTime(); // 随机数,作为水印,只加载一次
var watermarkvalue = “FirstCatch:”+document.domain+”|”+ts;
//alert(watermarkvalue);
if (anehta.dom.checkCookie(“anehtaWatermark”) == false){ // cookie中没有水印
if (anehta.detect.flash(‘8’) == true){ // 检测是否有flash
// 插入水印flash; 加载flash需要时间
anehta.inject.injectFlash(“anehtaWatermark”, watermarkflash, document.domain);
//alert(1);
setTimeout(function(){
if ( anehta.core.getWatermark(“anehtaWatermark”) == undefined ){
// flash cache 中没有记录,需要设置一个
anehta.core.setWatermark(“anehtaWatermark”, watermarkvalue);
}
// 读取水印并写进cookie
anehta.dom.addCookie(“anehtaWatermark”, anehta.core.getWatermark(“anehtaWatermark”));
anehta.dom.persistCookie(“anehtaWatermark”); // 让水印不过期
// 记录当前cookie
anehta.logger.logCookie();
},
500);
} else { // 不支持flash
// 在cookie里添加水印
anehta.dom.addCookie(“anehtaWatermark”, watermarkvalue);
anehta.dom.persistCookie(“anehtaWatermark”); // 让水印不过期
anehta.logger.logCookie();
}
}
else { // cookie 中有水印, 不需要重复记录cookie了
//检查flashcache中是否有水印,如果没有,则把cookie里的水印写入flashcache
if (anehta.detect.flash(‘8’) == true){ // 检测是否有flash
// 插入水印flash; 加载flash需要时间
anehta.inject.injectFlash(“anehtaWatermark”, watermarkflash, document.domain);
setTimeout(function(){if ( anehta.core.getWatermark(“anehtaWatermark”) == undefined ){
// flash cache 中没有记录,需要设置一个
anehta.core.setWatermark(“anehtaWatermark”, anehta.dom.getCookie(“anehtaWatermark”));
}
},
500);
} else { // 不支持flash
// do nothing
}
}
抢个座。。。网络安全刚学了水印!