Exploiting CORS:SOP与Jsonp劫持
in PENETRATION with 0 comment

Exploiting CORS:SOP与Jsonp劫持

in PENETRATION with 0 comment

简介


emmmmm,jsonp劫持已经是大佬们玩的剩下的了,然而在较大型的企业中还是存在不少的这种类型的漏洞,所以还是有必要学一学的。为了保护用户的安全,现代浏览器都使用了同源策略,不允许访问非同源的页面。然而还是有很多的需求去访问不同源页面的数据,怎么办?浏览器表示,拖鞋是不可能拖鞋的,一辈子都不可能拖鞋的。所以就出现了跨域这种概念。jsonp作为一种跨域方案,被广泛应用在较大互联网站点,而如果这种跨域方案存在安全问题,攻击者也可以利用。

SOP


惯例,在了解jsonp劫持之前,先将前置的各种概念解释清楚。同源策略(SOP),何为同源:

同协议
同域名
同端口

例:https://drops.org.cn与:
http://drops.org.cn 不同协议
https://test.drops.org.cn 不同域名
http://drops.org.cn:8000 不同端口
于是它们都是不同源的。

正确了解SOP策略

如果不加注意,你也许会认为同源策略就是浏览器简单粗暴地阻止浏览器去请求,而恰恰相反,浏览器不会阻止脚本去访问,而是阻止Response。用一个小例子来试验一下。

<script src="http://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js">
$.get('https://drops.org.cn/catch.php')
</script>

catch.php是放在服务器的一个脚本,记录访问日志,将ip等信息写入文件。
对以上代码进行测试发现:
jsonp.jpg

服务端:
jsonp2.jpg

同源策略阻止了返回资源。这个时候就有人会想到,既然是浏览器阻止返回资源,那么在CSRF攻击利用中,即使无法载入资源,攻击请求已经发出。是不是可以在只验证referer的CSRF中伪造referer达成CSRF攻击。我们试验JQuery在一个Ajax添加定制referer头。

<script type="text/javascript" src="http://cdn.static.runoob.com/libs/jquery/1.8.3/jquery.js">
</script>
<script type="text/javascript">
    $(document).ready(function(){
        $.ajax({
            type : "get",
            async: false,
            headers: {
              'Referer':'https://drops.org.cn'
            },
            url : "https://drops.org.cn",
            type: "json",
            success : function(data) {
                alert(data)
            }

        });
    });
</script>

当请求时,会发现浏览器阻止Ajax伪造Referer:
jsonp3.jpg

跨域与jsonp


同源策略虽然提高了安全性,但也给开发者造成了不便。于是一些常见的跨域解决方案便出现了:

  1. 降域
  2. CORS:跨域资源共享
  3. jsonp:Json With Padding

降域使用于在子域名较多时,在js中使用document.domain降域为主域,于是整个子域都能去获取主域或则相互间加载。
CORS跨域资源共享是一个W3C标准,是标准的跨域方案。简单来说,就是服务器只需要合理设置Access-Control-Allow-Origin,Access-Control-Allow-Credentials,Access-Control-Expose-Headers三个字段,客户端请求时加入Origin:字段,服务端判断该Origin是否在Access-Control-Allow-Origin规则中,若满足规则,则能成功请求数据。详细的CORS原理可在http://www.ruanyifeng.com/blog/2016/04/cors.html
查看,写的非常详细。本文不再过多解释。
jsonp:在html标签里,一些标签利用src,href等属性去加载资源是没有跨域限制的。于是聪明的程序员就发明了jsonp这种跨域方案,虽然应用广泛,但却不是官方的。常见的可跨域标签有

<script src="..."></script>
<img src="...">
<video src="..."></video>
<audio src="..."></audio>
<embed src="...">
<frame src="...">
<iframe src="..."></iframe>
<link rel="stylesheet" href="...">
<applet code="..."></applet>
<object data="..." ></object>

而jsonp就是利用scriptsrc属性可加载任意资源的原理去进行跨域数据传输。
在现在的web等应用程序中,使用json 传输数据是不二之选,但由于浏览器同源策略限制,javascript无法直接去获取接口json数据。jsonp其实就是将json数据封装在一个js函数中,由sciptsrc去请求并返回这个函数。客户端获取到该函数之后执行该函数,我们暂时将此过程称之为一个callback
而客户端要运行一个js函数,则需要知道这个函数的名字,这时服务端就不能去定义一个死的函数名,这样会造成业务间的高耦合,也不安全。因此这个函数名需要客户端去传输过来,服务端将请求函数名和json数据封装。这个过程在客户端表现为jsonp需要一回调函数。接下来举个简单的例子:
服务端的代码如下

<?php
header('Content-type: application/json');
//获取回调函数名
$jsoncallback = htmlspecialchars($_REQUEST ['jsoncallback']);
//json数据
$json_data = '["customername1","customername2"]';
//输出jsonp格式的数据
echo $jsoncallback . "(" . $json_data . ")";
?>

这个可以在http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=dr0op请求。可以发现返回数据包如下:

dr0op(["customername1","customername2"])

jsoncallback传递过去的就是函数名。服务端返回的是一个函数调用。可以理解为dr0op是一个函数,其中的["customername1","customername2"]是函数参数,也是我们要传输的数据。而客户端只需要去编写一个dr0op函数,接收参数并处理,就获取到json数据了。这就是一个callback
客户端可编写如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP 实例</title>
</head>
<body>
    <div id="divCustomers"></div>
    <script type="text/javascript">
function dr0op(result)
        {
            var html = '<ul>';
            for(var i = 0; i < result.length; i++)
            {
                html += '<li>' + result[i] + '</li>';
            }
            html += '</ul>';
            document.getElementById('divCustomers').innerHTML = html;
        }
</script>
<script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=dr0op"></script>
</body>
</html>

客户端获取数据库将数据写入ul节点中。查看输出:

jsonp4.jpg

可以发现,成功获取到数据。

jsonp劫持


如果jsonp传输的数据是较为敏感的数据,但是服务端并没有对客户来源页referer合理检测,那么攻击者只需要伪造一个页面,类似CSRF攻击那样,就可以获取敏感数据了。
这里来说一个典型的黑产案例:
有时候你不小心点击到了某个培训,医疗,或者保险之类的网站,你并没有去输入你的手机号,等一会就会有人打电话过来,问你需不需要他们的产品。这是黑产挖掘到了运营商的一个漏洞,然后利用漏洞泄漏用户手机号,将手机号发送到后台。其实这个漏洞有一部分就是jsonp劫持导致的:

jsonp5.jpg

jsonp6.jpg

至于为什么手机进行web访问运营商接口,运营商就可以获取手机号。大致因为运营商可以依据当前手机移动窝蜂网络如4G等,依据网络认证获取SIM卡手机号(非HTTP协议)。
具体的原理或许只有运营商通信商掌握。

jsonp劫持获取QQ号:

jsonp7.jpg

jsonp劫持泄漏信息:

jsonp8.jpg

空referer绕过检测

和CSRF一样,防御jsonp劫持可以去检测referer,由于直接使用浏览器打开为空的referer,而检测也会通常忽略这一点,只要攻击者让用户点击时利用浏览器特性发送空referer,即可桡过检测。
如,在iframe 标签中使用javascript伪协议来实现空referer:

<iframe src="javascript:'<script>function JSON(o){alert(o.userinfo.userid);}</script><script src=http://www.qq.com/login.php?calback=JSON></script>'"></iframe>

也可以时候data伪协议实现:

data:text/plain; base64,our_base64_encoded_code

jsonp9.png

jsonp劫持防御


1、严格安全的实现 CSRF 方式调用 JSON 文件:限制 Referer 、部署一次性 Token 等。
2、严格安装 JSON 格式标准输出 Content-Type 及编码( Content-Type : application/json; charset=utf-8 )。
3、严格过滤 callback 函数名及 JSON 里数据的输出。
4、严格限制对 JSONP 输出 callback 函数名的长度(如防御上面 flash 输出的方法)。
5、其他一些比较“猥琐”的方法:如在 Callback 输出之前加入其他字符(如:、回车换行)这样不影响 JSON 文件加载,又能一定程度预防其他文件格式的输出。还比如 Gmail 早起使用 AJAX 的方式获取 JSON ,听过在输出 JSON 之前加入 while(1) ;这样的代码来防止 JS 远程调用。

REFERENCE

[1] https://www.anquanke.com/post/id/97671
[2] https://segmentfault.com/a/1190000015597029
[3] http://www.ruanyifeng.com/blog/2016/04/cors.html
[4] https://blog.csdn.net/u011897301/article/details/52679486
[5] http://blog.knownsec.com/2015/03/jsonp_security_technic/

Responses