Anehta的水印(Watermark)机制

来源:互联网 发布:seo黑帽手法有哪些 编辑:程序博客网 时间:2024/05/22 17:11

 Anehta中采用了一种同机识别的技术,我在项目中将其称为“水印”(Watermark).

看过我的录像演示的人应该有印象,效果如下:

如果一个客户端被打上了水印,那么,不管客户端删除了cookie、缓存,抑或是切换了各种不同的浏览器,其水印都不会变化

换句话来说,就是常规的清除上网痕迹的措施,都无法清除掉anehta给客户端打上的水印。

这看起来好像跟变魔术一样,其实揭穿了很简单,我是通过Flash的shared objects来做的,也可以称作flash cookie

其实这种技术在比较早的时候foundstone的paper中就提到过了,同时还有提到的是一个IE persistence Data,会保存在IE临时文件的一个index.dat中,也是光删cookie或缓存删不掉的。但是这个持久数据在IE7中已经不能再这么利用了,所以我这里仅仅使用了flash的cookie。

yahooalibaba都使用了这种技术用在登录入口来防范钓鱼的威胁。

正常来说,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
}    
}

原创粉丝点击