JSONP漏洞学习笔记

JSONP的产生

同源(在同一个域),就是两个URIs具有完全相同的协议主机端口号

1.首先,Ajax直接请求普通文件存在跨域无权限访问的问题;

在本地测试,使用XHR:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript">
var xhr = new XMLHttpRequest();
//异步接收响应
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
} };
xhr.open("get", "http://127.0.0.1/1.html", true);
//xhr.open("get", "http://www.gtfly.top", true); //指定请求方法和URL,第三个参数true表示异步获取响应
xhr.send(null)
</script>

当请求的地址是http://127.0.0.1/1.html,会正常返回请求结果:

当访问http://www.gtfly.top,显示请求失败:

2.不过在页面调用JS文件时不会收到跨域的影响,而且凡是拥有src属性的标签都有跨域能力,比如scriptimg

在本地测试,使用script引用远程JS文件:

1
2
<script type="text/javascript" src='http://www.gtfly.top:100/1.js'>
</script>

VPS新建1.js,写入:

alert`1`

本地访问,成功执行alert命令:

3.JSONP全称为JSON with Padding,它允许用户传递一个callback参数给服务端,之后服务端返回数据时会将callback参作为函数名来包裹住JSON数据,这样客户端便可自动处理返回数据了

现在尝试使跨域的数据来调用本地函数,本地JS:

1
2
3
4
5
6
7
<script type="text/javascript">
var localHandler = function(data){
alert("获取的data: "+data.result);
}
</script>
<script type="text/javascript" src="http://www.gtfly.top:100/1.js">
</script>

这里远程使用json格式的内容,1.js:

localHandler({"result":"i am remote data"})

那么这样便可跨域获取数据,但要怎么让远程JS知道它应该调用的本地函数叫什么名字呢?

调用者可以传一个参数给服务端用来表示“我需要调用X函数”,之后服务端就按照客户端的需求来生成JS脚本并响应;我们更改上述静态Json数据,使用PHP改为动态生成的数据;1.php:

1
2
3
4
5
6
7
8
<?php
$func = $_GET['callback'];
$name = $_GET['name'];
$score = 100; // query($name)
echo "$func({
\"name\":\"$name\",
\"score\":\"$score\"
})";

同时更改前端JS代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<script type="text/javascript">
var getScoreHandler = function(data){
alert("获取的"+data.name+"的分数:"+data.score);
}
# 返回JSON数据的URL
var url = "http://www.gtfly.top:100/1.php?name=gtfly&callback=getScoreHandler";
# 创建script标签
var script = document.createElement('script');
# 设置src
script.setAttribute("src", url);
# 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>

这里使用GET方式,将查询的参数以及即将调用的本地JS函数名传给了1.php,1.php接收后进行相应的查询,并生成数据返回;本地获取到数据后便会调用相应的全局函数

为了方便,我们可使用JQuery实现JSONP调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript" src="https://common.cnblogs.com/scripts/jquery-2.2.0.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
$.ajax({
type: "get",
async: false,
url: "http://www.gtfly.top:100/1.php?name=gtfly",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"getScore",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
alert(json.name+"的分数:"+json.score);
},
error: function(){
alert('fail');
}
});
});
</script>

JSONP常见漏洞

1.未授权访问

通过控制查询参数,例如id、name等访问未授权的资源

2.参数注入

通过控制参数来控制返回前端的内容,可能产生XSS等漏洞

以上就是JSONP相关的内容

再看一下CORS解决跨越

我们以PHP为例,通过CORS来解决这个问题(具体可参考文章,总结了9种解决跨域的方法,包括JSONP);服务端1.php:

<?php
echo "hello";
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Origin: *");