WebSth 指纹识别插件简要分析
WebSth 指纹识别插件简要分析
今天才在某个论坛上看到这个网站:http://websth.com/, 深感所知甚晚啊,自己一直想做的web指纹识别,已经有童鞋做成chrome插件发布了,并且功能还算比较强大,不过准确性确实有待提高。于是我下载了其源码并开始围观一下。
先看看识别效果:
之前接触过chrome插件的开发(只是看过一部分文档),所以对插件的运行流程有所了解。
代码的文件结构是这样:
其中有一个manifest.json,一个json格式的文件,读过文档的就知道这个文件其实是chrome加载插件的主文件,里面配置了一些关于插件的信息。我们打开参观一下:
{
"name": "__MSG_extName__",
"description": "__MSG_extDescription__",
"permissions": [ "http://*/*", "https://*/*", "tabs", "storage" ],
"version": "1.1.0",
"manifest_version": 2,
"default_locale": "en",
"icons": {
"128": "icon-128x128.png"
},
"background": {
"scripts": [
"js/web_technologies.js",
"js/web_servers.js",
"js/oses.js",
"js/web_front_libraries.js",
"js/web_apps.js",
"js/background.js"
],
"persistent": true
},
"content_scripts": [ {
"js": ["js/website_analyzer.js"],
"matches": [ "http://*/*", "https://*/*" ],
"run_at": "document_end"
} ],
"options_page": "options.html",
"page_action": {
"default_popup": "popup.html"
}
}
不长,里面有一个content_scripts字段,这个字段表示在web页面内运行的javascript脚本。chrome插件其实就是javascript脚本,所有的功能用脚本的形式执行。每当打开匹配url的页面时,就执行content_scripts里指定的脚本,这里是js/website_analyzer.js。
于是我们跟踪一下,打开js/website_analyzer.js。,发现其中代码功能是ajax获取当前访问的网页内容,并传递给扩展。其中定义了这样一个对象:
var data = {
"header" : this.getAllResponseHeaders(),
"dom" : covertNodes(document),
"hostname" : hostname,
"port" : document.location.port
};
这个对象就保存了http头、DOM对象、域名和端口。然后通过 chrome.extension.sendMessage(data) 传递给我们的插件。
返回到我们的manifest.json中,还能找到一个background字段,里面保存了不止一个的js文件,这些js文件就是运行在我们插件整个生命周期中的脚本。其中有一个background.js,它接受到了浏览器页面传递来的data数据,然后对它进行处理。
打开background.js文件,略长,我们只分析web指纹那个部分。
// match web apps
var apps = []
for (var i in web_apps) {
for (var j in web_apps[i]['rules']) {
if (findNode(root, web_apps[i]['rules'][j].type, web_apps[i]['rules'][j].match, web_apps[i]['rules'][j].name, web_apps[i]['rules'][j].attributes)) {
apps.push(web_apps[i]);
break;
}
}
}
technologyData[sender.tab.id]['web_apps'] = apps;
因为在加载background.js之前加载了一个web_apps.js,里面定义了一个web_apps对象,就类似一个数据库,保存着很多指纹信息。我们这里就用一个for in循环,遍历web_apps对象,在其中匹配查找。内层还有一个for in循环,进行多个条件下的匹配。比对用到findNode这个函数,这个函数在background.js中:
function findNode(root, type, text, name, attr){
// type = [
// 1, // element
// 3, // text
// 8 // comment
// ]
// text = reg to search
// name = element tagName
// attr = element attr to search
for (var node in root){
if(type == 1 && root[node].nodeType == type){ // element
if (root[node].nodeName.toUpperCase() == name.toUpperCase()){
var search_str = root[node].attributes[attr.toLowerCase()];
if (search_str.match(text)){
return true;
}
}
}else if(root[node].nodeType == type){ // text & comment
if (root[node].nodeValue.match(text)) {
return true;
}
}
}
return false;
}
第一个参数root是DOM,后面几个参数表示比对的内容。这个函数用一个for in循环遍历了整个DOM,如果是元素(element,type=1)节点,就比较其name元素的attr属性是否和text匹配(type/name/attr/text是传入的参数),如果是文本(TEXT/COMMENT, type=3 or 8)节点,就直接比较该文本是否和text匹配。
我们举个例子,比如discuz的规则:
{
"icon": "discuz.jpg",
"title": "Discuz!",
"url" : "http://www.discuz.net",
"rules": [
{
"type": 1,
"name": "SCRIPT",
"attributes": "src",
"match": "logging\.js"
},
{
"type": 1,
"name": "META",
"attributes": "content",
"match": "Discuz\!"
},
{
"type": 3,
"name": "TITLE",
"attributes": "",
"match": "Powered by Discuz\!"
},
{
"type": 1,
"name": "A",
"attributes": "href",
"match": "^home.php\?mod=space"
}
]
},
我们看rules的第一项,type=1,表示元素节点,也就是说我们查找,如果找到“script”元素的“src”属性和"logging\.js"匹配(通俗来说就是找到<script src="...logging.js"></script>),这里就返回true.
因为discuz的规则有四个,我们看代码发现,只要有一个满足就跳出,匹配下一个web app,所以准确度不高,只能说是疑似discuz。像我之前那个截图一样,出现了dedecms和pwiki两个可能,还需要进一步的确认才行。
填充了apps这个对象以后,把它保存 technologyData[sender.tab.id]['web_apps'] = apps;
主目录下还有一个popup.html,作用就是我点击插件的按钮,弹出的那个小框的html代码。打开发现就是一个什么内容都没有的html,但最后加载了js/popup.js这个脚本。这个脚本就是把technologyData中的内容取出来,写到popup.html里,让用户看。
打开popup.js,看到web指纹那个部分。
找到如下代码:
if (data['web_apps'].length != 0) {
var tr = document.createElement('tr');
var td1 = document.createElement('td');
td1.innerHTML = "<strong>";
td1.innerHTML += chrome.i18n.getMessage("webApps");
td1.innerHTML += "</strong>";
var td2 = document.createElement('td');
td2.setAttribute("colspan", "2");
for (var i in data['web_apps']) {
if (data['web_apps'][i].url){
// td2.innerHTML += "<a href="" + data['web_apps'][i].url + "" target="_blank"><img class="img" width="19px" hight="19px" src="icons/" + data['web_apps'][i].icon + "" /> " + data['web_apps'][i].title + "</a>";
td2.innerHTML += "<a href="" + data['web_apps'][i].url + "" target="_blank"><img class="img" width="19px" hight="19px" src="icons/" + data['web_apps'][i].icon + "" title="" + data['web_apps'][i].title + "" /> " + data['web_apps'][i].title + "</a> ";
}else{
td2.innerHTML += "<img class="img" width="19px" hight="19px" src="icons/" + data['web_apps'][i].icon + "" /> " + data['web_apps'][i].title + " ";
}
}
tr.appendChild(td1);
tr.appendChild(td2);
document.getElementById("detail").appendChild(tr);
}
没什么好说的,就是一个一个取出来,加进html里。
最后,我们梳理一遍流程:
1.打开浏览器,预先加载插件的javascript,比如background.js等
2.进入一个网站:discuz.net
3.加载js/website_analyzer.js,通过ajax获得所访问网站的DOM和其他信息
4.background.js获取到DOM,执行一个for in 循环,遍历web_apps对象,对其中每一个web app类型做比对。比对过程是遍历DOM,发现匹配就退出,执行下一次比对。
5.返回比对结果。如果此时用户点击插件按钮,即弹出popup.html,其中执行popup.js,该js把相关信息写入popup.html让用户查看。
读过代码后知道这个插件是靠DOM元素的匹配来识别某个web指纹,相比于其他一些比如md5指纹识别要更适合javascript,可扩展性也好(我们可以修改web_apps.js来手工添加一些web指纹信息)。
- 初识MongoDB分片
- Linux上安装Redis
- SpringBoot+WebSocket实现在线聊天(二)
- SpringBoot中使用Freemarker构建邮件模板
- SpringBoot中发送QQ邮件
- SpringBoot中使用POI,快速实现Excel导入导出
- 代理技术 | 重磅,代理服务器背后的故事(正向、反向代理)
- SpringBoot中自定义参数绑定
- ElementUI中tree控件踩坑记
- 一个隐马尔科夫模型的应用实例:中文分词
- 使用MyBatis轻松实现递归查询与存储过程调用
- Config Server——使用Spring Cloud Bus自动刷新配置
- Config Server——配置内容的加密与解密 详解
- 使用 HTML5 WebSocket 构建实时 Web 应用
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【Netty】02-netty中不得不说的粘包与拆包
- 【不可思议的CANVAS】画一只会跟着鼠标走的小狗
- 【Netty】03-实战之序列化与反序列化协议
- JDK15正式发布,划时代的ZGC同时宣布转正
- 一文掌握开发利器:正则表达式
- 探讨iOS 图片解压缩到渲染过程
- iOS Abort 问题系统的解决方案
- 【jvm】01- java内存结构分析
- 【redis】01-redis简介
- 3000字详解四种常用的缺失值处理方法
- python学习笔记(7)——远程主机强迫关闭了一个现有的连接
- 【带你成为pyq最靓的仔】朋友圈九宫格(一)之图片切割篇
- Material Design Compoents 1.1.0
- 【第19期】HTTP请求头referer
- Sentinel流控日志与索引