什么是JSON劫持
单从字面上就可以理解的出来,JSON是一种轻量级的数据交换格式,而劫持就是对数据进行窃取(或者应该称为打劫、拦截比较合适。恶意攻击者通过某些特定的手段,将本应该返回给用户的JSON数据进行拦截,转而将数据发送回给恶意攻击者,这就是JSON劫持的大概含义。一般来说进行劫持的JSON数据都是包含敏感信息或者有价值的数据。
造成JSON劫持漏洞的成因
正所谓无风不起浪,无根不长草,要发动一次成功的JSON劫持攻击必须要有这些先决条件
1、受攻击的网站URL返回一个JSON对象或者数组,并且返回的数据有重要的价值,也就是敏感的数据。(PS:JSON Hijacking 里说只支持数组,但是对象也是可以进行劫持的,具体在下面的流程中会说明)
2、受攻击的网站地址支持GET请求的响应(PS:其实POST请求也可以做到JSON劫持,只不过需要对受害人进行诱导提及表单以发送POST请求。相比GET请求来说十分麻烦
3、受害人的浏览器没有禁用javascript(PS:现在一般也不会禁用js,毕竟目前许多网站都依赖于脚本所展现的强大功能和绚丽的效果)
4、受害人浏览了钓鱼/恶意网站,并且受害人在受攻击的网站中,保存在COOKIE中的身份验证信息尚未清除。(PS:除非受攻击的站点没有做任何的身份验证!一般响应重要数据的JSON服务都是需要做身份验证的)
5、受攻击的站点没有做相关的防御措施
JSON劫持攻击的流程和手段
一、进行JSON劫持的第一步就是恶意攻击者要确定攻击的网站,一般会挑选大众常去的网站或者有价值的网站(购票网站、网购网站、论坛等)。由于大部分使用JSON作为数据传输的网站往往会使用到AJAX技术,而AJAX作为前端脚本,存在着透明性和公开性。这样导致的结果是增加了攻击层面和入口,为攻击者添加了更多的选择和便捷。
所以恶意攻击者常常浏览网站的脚本来寻找漏洞进行攻击,一但确定网站存在JSON劫持漏洞,即某个JSON服务或者接口返回有价值的敏感的JSON数组数据,那么攻击者就会针对这个网站进行JSON劫持攻击。(这里假设我们要攻击的站点地址是:http://vulnerable.shiyousan.com/Home/GetJson,PS:该URL假设是一个JSON服务和接口,会返回一个敏感的JSON数组数据)
服务器的代码如下:
[HttpGet]
[Authorize]
public ActionResult GetJson()
{
//这里使用了隐式类型的数组,C#3.0的新特性
var result=new[]{new {Id=1,Name="张三"},new {Id=2,Name="李四"}};
return Json(result, JsonRequestBehavior.AllowGet);
}
另外可以看到这里设置了JsonRequestBehavior.AllowGet参数,如果不设置会提示如下错误:“此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站。若要允许 GET 请求,请将 JsonRequestBehavior 设置为 AllowGet。”
我们可以看到现在ASP.NET MVC默认是禁止使用GET请求来获取JSON数据的,微软默认已经为JSON劫持做了防御措施。(详情点击此链接)
二、在第一步明确了要攻击的站点后,恶意攻击者第二步就是要诱骗受害人点击和进入到钓鱼/恶意网站,这点是十分重要的,所以恶意攻击者常常在网络上通过各种方式诱骗受害人进入到他们精心布置的陷阱中。
常用的方式有以下几种:
1、通过邮件群发,发送大量垃圾/钓鱼邮件等待受害者点击邮件中的链接。一般此类邮件的标题和内容往往是十分吸引人的,比如:点击这个链接看美女/点击链接观看超级有趣的视频/揭秘某某明星的秘密之类的链接。当然,这里的只是随便举例,真正高明的欺诈师往往在内容上会做一定的处理,让你神不知鬼不觉的进入到恶意网站中。
2、通过社交软件和网站发送链接,随着各种社交软件和网站的崛起,在信息传播方面也变得更加便捷与迅速。与此同时也给恶意攻击者提供了更加便捷的钓鱼和攻击方式。
3、还有其他的各种方式,比如论坛发帖啦,前阵子的超级手机病毒蝗虫(通过短信诱骗受害人下载病毒),还有各种即时通讯工具(QQ群或者陌生人的链接不要乱点)等。
三、一旦受害人点击了恶意链接进入到钓鱼网站中,那么接下的第三步就是劫持受害人的数据了。结合我所查阅的资料,在受害人进入到恶意钓鱼网站后,恶意网站会进行下面这些流程:
1、首先会向进行攻击的目标网站发送一个GET请求(如第一步所说的,假设攻击的URL是http://vulnerable.shiyousan.com/Home/GetJson,这个URL会返回一些重要的JSON数组数据),只要在网页中放置这句代码,就会自动朝目标发送一个HTTP GET请求:
<script src="http://vulnerable.shiyousan.com/Home/GetJson"></scirpt>
如果目标URL地址只支持POST请求,那么攻击者可能要费一番功夫,诱导受害人点击提交表单,从而发生一次POST请求。
另外就向上面所说的JSON劫持形成的先决条件那样,敏感数据的获取都是需要进行身份验证的,这也是JSON劫持的另一个特殊点。受害人一进入钓鱼网站,就向受攻击的网站发送GET请求,而由于GET请求是从受害人的浏览器发出的,所以请求发送的同时也会将受害人在网站中身份验证信息的cookie一同发送给受攻击的站点,这样一来就等于是恶意攻击者伪装成受害人,伪装成一个合法的用户。而受攻击的网站因为这个合法的身份,就会将敏感的JSON数组数据响应给钓鱼/恶意网站。
PS:这里额外说明下,一般身份验证信息在COOKIE中保存的只是一个会话ID,而真正的会话是保存在服务器上的,但是攻击者只要获取到这个会话ID并发送给网站,就可以匹配到受害者的身份验证会话,即等于成功的伪装成受害者,这其实也是一种CSRF(跨站请求伪造)攻击。
2、恶意网站成功发送一个带有身份验证信息的GET请求后,成功的获取到了攻击站点返回的数据,响应的数据需要是JSON数组或者JSON对象。一般都是返回JSON数组,如果返回JSON对象网站需要经过特殊处理,比如返回{"Id":1, "Name":"张三"}这样的JSON对象,浏览器会提示非法标签错误,所以服务器上需要在返回的JSON上添加小括号:({"Id":1, "Name":"张三"})。
到了这一步是最关键的地方,攻击者接下要做的就是将响应到钓鱼网站的数据发送到自己服务器的数据库上,这就是将数据劫持了。因为此攻击是针对JSON格式的数据,所以也称为JSON劫持。
那么攻击者是如何将数据劫持走的呢?这里就需要用到JS中的方法覆盖的特性或者使用JS的特殊方法__defineSetter__(__defineSetter__存在浏览器兼容问题,所以一般是使用JS的方法覆盖)。具体的原理可以查看这篇文章:《Javascript方法的覆盖和重写》。攻击者通过javascript中可以覆盖掉其他方法的特性,将响应给恶意网站的JSON数组或者对象进行构造函数的替换。
具体代码如下:
<script type="text/javascript">
function Array() {
//这里假设返回的JSON数组是:[{ "Id": 1, "Name": "张三" }, { "Id": 2, "Name": "李四" }]
var jsonData = this;
var message = '[';
for (var index in jsonData) {
message += '{"Id":' + jsonData[index].Id + ',"Name":"' + jsonData[index].Name + '"}';
}
message += ']';
/*
* 弹出返回的数据,这里我们只是将劫持到数据弹出,
* 而恶意攻击者则会在这里将劫持到的JSON数据传送到他们的服务器中
*/
alert(message);
}
</script>
当JSON数据响应给网站时,浏览器立即会调用数组或者对象的构造函数。正是利用这一点,把构造方法替换成恶意代码,在构造方法中添加将JSON数据发送给第三方即攻击者的代码。到了这里就成功的完成了整个JSON劫持攻击的流程!!!
如何防御JSON劫持
防御要从两方面着手,一是网站方面必须做好防御机制,二是用户也需要提高警惕。
先从网站方面来说,其实JSON劫持是一种变相的CSRF(跨站请求伪造)攻击,所以使用通常应对CSRF攻击的常规手段就可以很好的防御住此类攻击,通常是使用访问令牌,token机制就可以较好的防御住攻击,在发送请求的时候必须将token令牌也发送给JSON服务,这样基本可以杜绝此类攻击。
还有敏感和重要数据的请求入口一定要设置身份验证,而且最好限制只能POST请求,虽然这不能完全的防御住攻击(基本上可以杜绝大部分攻击),但是可以为攻击者添加难度,ASP.NET MVC中只需要在控制器的Action中声明[HttpPost]特性就可以了。此外最好能判断请求的来源,设置请求的黑白名单,这样能极大的提高安全性。
另外从用户方法来说,提高网络安全意识也是很重要的。程序中总会存在各种各样的漏洞,漏洞无处不在,只有还未修复和破解的漏洞,只有还未发现和产生的漏洞。所以我们适当的提供一点安全意识,不随意点击来路不明的链接,这样可以减少进入钓鱼网站的概率。
除此之外,还要注意保护自己的相关信息不被非法窃取和利用,毕竟如果黑客不知道我们的任何联系方式(包括邮箱,手机号,QQ等即时通讯工具号),那么就会减少被黑客盯上的概率。