JSONP 跨域及攻击

JSONP 跨域介绍

原理:<script> 是可以跨域的,而且跨域脚本可以直接回调当前脚本的函数

script 标签可以加载异域的 js 并执行,通过预先设定好的 callback 函数实现。称为 JSONP (JSON with Padding)跨域,JSONP 是一非官方的协议。因为 callback 函数通过 JSON 来进行传参,将 JSON 数据填充到回调函数,所以叫 JSON + Padding。 JSONP 只支持 GET 请求

前端代码:

# www.zzzsdust.com/a.html

<script type="text/javascript">
    function dosomething(jsondata){
        alert(jsondata);
    }
</script>
<script src="http://www.n0th1ng.top./data.php?callback=dosomething"></script>

后台代码:

# www.n0th1ng.top./data.php

<?php
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

访问 www.zzzsdust.com/a.html 后会弹出 a,b,c

JSON Hijacking (JSON 劫持)

JSON Hijiacking 属于 CSRF 攻击,当某网站通过 JSONP 的方式来跨域传递用户认证后的敏感信息时,攻击者可以构造恶意的 JSONP 调用页面,诱导被攻击者点击访问来截取用户敏感信息,一个典型的 JSON HiJacking 攻击代码:

# www.hacker.com/hacker.html
<script>
function wooyun(v) {
    alert(v.username);
}
</script>
<script src="http://js.login.360.cn/?o=sso&m=info&func=wooyun"></script>

当用户在已经登录 360 网站的情况下访问如上 www.hacker.com/hacker.html 网页,那么用户的隐私数据就可能被攻击者劫持。

防御手段通常有两种:

  • Referer 检查
  • 添加 token

Referer 检查

这个方案是主要利用了 <script> 远程加载 JSON 文件时会发送 Referer ,在网站输出 JSON 数据时判断 Referer 是不是白名单合法的就可以进行防御,这个方法是可行的,但是具体实现过程中又容易导致 2 种常见的逻辑问题:

  • Referer 过滤(正则不严谨),比如 http://www.qq.com/login.php?calback=cb 输出数据时,使用了 Referer 过滤。但是可惜过滤的时候只过滤了 Referer 里是否存在 qq.com 这样的关键词,那么攻击者可以听过构造 URL:http://www.qq.com.attack.com/attack.htm 或者 http://www.attack.com/attack.htm?qq.com 这样的页面来发起攻击实现绕过 Referer 防御
  • 空 Referer,开发者在部署过滤 Referer 来源时,忽视了一个空 Referer 的过滤。一般情况下浏览器直接访问某 URL 是不带 Referer 的,所以很多防御部署是允许空 Referer 的。恰恰也就是这个忽视,导致了整个防御的奔溃。因为在通过跨协议调用 js 时,发送的 http 请求里 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> 代码里使用 <iframe> 调用 javscript 伪协议 来实现空 Referer 调用 JSON文件。另外还有 data:text/jpeg;base64,XINGSXXIANGJIJIGSAG== 协议等。

添加 token

如同普通的 CSRF 攻击防御一样,添加随机token 进行防范,值得注意的是 token 必须是请求一次更换一次,否则可以暴力破解 token。

Callback 可定义导致的安全问题

上述代码:

# www.n0th1ng.top./data.php

<?php
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

中 callback 是可自定义的,这个可定义的 callback 是可输出的,又导致了各种安全问题:

  • Content-Type 与 XSS 漏洞

Content-Type 与 XSS 漏洞

在输出 JSON 时没有严格定义Conten-Type(Conten-Type:application/json) (PHP 中默认为 Content-Type: text/html; charset=UTF-8),再加上 callback 没有进行过滤导致 XSS 漏洞:

www.n0th1ng.top./data.php/x.html?callback=<script>alert("xss")</script>

经测试,在谷歌浏览器(版本 75.0.3770.142(正式版本) (64 位))不会弹窗,在火狐浏览器(66.0.5 (32 位))中会弹窗。

防御手段:

  • 严格定义 Content-Type:application/json,这种方法能够让浏览器不解析恶意插入的 XSS 代码(直接访问提示文件下载)
  • 过滤 callback 及 JSON 数据输出,已经严格定义编码方式,防止编码绕过 Content-Type: application/json; charset=utf-8

参考链接: