JS劫持
JS劫持和JS点击劫持,是完全两个漏洞哈,此文章为学习记录。
首先说明目前的主流浏览器创建数组对象时都默认不运行__defineSetter__设置好的函数,所以此类攻击已经近乎失效。
Javascript劫持与CSRF攻击原理非常相似,唯一不同的是,CSRF是模拟你的身份去发送请求,JavaScript Hijacking是模拟你的身份,窃取你在服务器上的私隐信息。
即在一个函数运行之前把它劫持下来,添加我们想要的功能。当这个函数实际运行的时候,它已经不是原本的函数了,而是带上了被我们添加上去的功能。这也是我们常见的钩子函数的原理之一。
- Javascript劫持通过重写Object的__defineSetter__方法来实现钩子。
- 服务器返回的数据是数组类型。
- 浏览器会将数组类型当作JS代码运行,创建了一个数组对象并设置属性。
- 重写的方法会先执行,方法中可获得设置的属性,使攻击者能够将JSON数据外发。
见下图:
(1).你正常访问信任站点(http://www.Bank.com),然后登陆信任站点。
(2).信任站点通过你的验证,并返回Cookie。
(3).这时,在你还没有登出信任站点之前,你再打开了一个浏览器的tab页,并访问了一个恶意站点(www.BadGuy.com)。
(4).恶意站点向请求用户访问http://www.Bank.com的一个资源。
(5).浏览器带着之前的Cookie信息,向信任站点http://www.Bank.com发出了一个GET请求。
(6).信任站点验证的Cookie信息通过,根据请求返回一个JSON数组(如果不清楚JSON,可以参考《JSON入门指南》)。
(7).你的浏览器收到来自http://www.Bank.com的响应后,转发响应中的JSON信息给恶意站点。
至此,恶意站点拿到你关于http://www.Bank.com的信息。
到这里,你应该有对JavaScript Hijacking有一个大概的概念,它确实和CSRF很相像,唯一不同的是,CSRF是模拟你的身份去发送请求,JavaScript Hijacking是模拟你的身份,窃取你在服务器上的私隐信息。
攻击步骤
我们先看下攻击代码
<script type="text/javascript">
Object.prototype.__defineSetter__('profile', function(obj) {
alert(obj);
});
</script>
<script type="text/javascript" src="http://127.0.0.1:9000/stored/json">
</script>
在用户访问恶意网站时:
<script type="text/javascript" src="http://127.0.0.1:9000/stored/json"
</script>
- 这段JS代码会要求浏览器发送一个GET请求到http://127.0.0.1:9000/stored/json,于是浏览器按照指示,带上本地的Cookie信息,发送一个http的GET请求。
- 服务器接受到请求后,确认身份后,响应请求返回了一个JSON数组/JavaScript代码段。
- 浏览器接受到这段JS脚本后,如果返回的是一个JSON数组,比如:[{“Id”:1,“Name”:zac,“profile”:10000}]JSON数组被认为是一段可执行的JavaScript脚本,于是浏览器会解析执行。
- 解析执行时,由于创建了个数组对象,并设置了属性,之前重写的prototype.defineSetter()会被执行。
攻击想要成功的一个大前提是,目标服务器返回的json数据是一个数组。
- 与CSRF相同,攻击者需要创建一个恶意网页,并诱导受害者点击。
- 并攻击者在恶意网页中重写了Object的__defineSetter__方法。重写此方法后导致所有对象设置属性时会先运行这个方法。
- 并且在恶意网页中通过<script>标签请求目标服务器的json数据,当返回的json数据是数组类型时,浏览器会将其当作JS代码运行,创建了一个数组对象并设置属性。
- 此前重写的方法会先执行,方法中可获得设置的属性,使攻击者能够将属性外发。
注意事项:
1、信任网站(步骤2)返回的内容必须是JSON数组,如果是JSON对象的话那么会发生JavaScript错误,但是我们可以在返回的时候检测返回的类型,如果是对象的话,那么我们也是可以在对象的前后加上中括号
2、劫持与JavaScript Hijacking技术的关系是在步骤五上面体现的,在步骤五的实现上是一定要通过JavaScript劫持去重写对象中的方法,从而记录信任网站中敏感信息的功能,所以JavaScript Hijacking的实现与劫持密不可分
3、信任网站必须响应一个GET请求
修复建议
- 验证请求的来源 referer
- 避免直接执行 javascript响应,如下:
<script src "http://www.example.com/object.json"></script>
- 推荐:
从服务器的角度来看, jascript劫持攻击类似于跨站点伪装请求,因此,防止跨站点伪装请求也就可以防止 JavaScript劫持攻击。
请求附带 随机值token / cookie (cookie本身遵循同源策略)
例:以下Javascript片段描述了这种"盲客户端"策略:
var httprequest = new XmlHttpRequest( );
...
var cookies= "cookies="+escape(document. cookie);
http_request.open('post',url,true);
httpRequest.send(cookies):
- 让服务器只对HTTP POST请求做出响应,而不回应任何HITP GET请求
- 防止直接执行响应
当服务器序列化某个对象时,该对象应包括一个前缀(也可以是后缀),从而使它无法通过< script>标签执行 Javascript。合法的客户端应用程序可以在运行 JavaScript前删除这些无关的数据。
例:该方法可以通过多种方式来实现。以下例子演示了两种方式。
第一种,服务器可以把以下指令作为消息的前缀:
while(1);
除非客户端删除这些前缀,否则对这个消息求值将把 Javascript解释器发送到一个无限的循环中,客户端搜索并删除如下前缀:
var object;
var req = new XMLHttpRequest();
req. open("GET","/object. json", true):
req.onreadystatechange = function ()(
if (req. readyState == 4)(
var txt= req.responseText;
if(txt substr(0, 9)=="while(1): "){
txt= txt.substring(10);
}
object= eval("("+ txt +")");
req=null;
}
};
req. send(null);
第二种,服务器可以在 JavaScript附近加注注释字符,这些注释字符必须在 JavaScript被送往eval()函数前删除。以下]SON对象已加入了一块注释:
/*
[{"frame":"Brian","Iname":"Chess","phone":"6502135600",
"purchases":"60000.00","email":"brian@example.com"}
]
*/
客户端可以搜索并删除如下注释字符:
var object;
var req = new XMLHttpRequest();
req. open("GET","/object. json", true):
req.onreadystatechange = function ()(
if (req. readyState == 4)(
var txt= req.responseText;
if(txt substr(0, 2)=="/*"){
txt= txt.substring(2,txt.length -2);
}
object= eval("("+ txt +")");
req=null;
}
};
req. send(null);
任何通过< script>标签来提取敏感 JavaScript的恶意站点都将无法获取其中所包含的数据。
自第5版 Ecmascript起,已不可能攻击 JavaScript数组构造函数.
参考文章:
https://www.cnblogs.com/hyddd/archive/2009/07/02/1515768.html
https://www.csdn.net/tags/MtTacgwsNzk3NjMtYmxvZwO0O0OO0O0O.html