JSONP攻防实例解析
前言
纸上得来终觉浅,绝知此事要躬行。
关于JSONP
Jsonp(JSON with Padding)是一种跨域请求资源的解决方案,JSONP可以绕过AJAX遵循的同源策略。
菜鸟教程存在数据(["customername1","customername2"]),我们希望在本地展示,由于受同源策略的限制,AJAX无法调用该页面。代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP 实例</title>
<script type="text/javascript">
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState === 4) {
// 判断响应结果:
if (request.status === 200) {
// 成功,通过responseText拿到响应的文本:
document.getElementById("text").innerHTML=xmlhttp.responseText;
} else {
// 失败,根据响应码判断失败原因:
return request.status;
}
}
}
// 发送请求:
request.open('GET', 'http://www.runoob.com/try/ajax/jsonp.php');
request.send();
</script>
</head>
<body>
<div id="text"></div>
</body>
</html>
访问测试:python -m SimpleHTTPServer开启HTTP服务器,默认端口8000,开启console结果如下

Callback
为了更好的使用第三方数据,第三方允许请求方使用自定义的callback名称。例如:http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=test,这里的jsoncallback参数是可以自定义的。

JSONP应用
菜鸟教程给出了一个demo。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP 实例</title>
</head>
<body>
<div id="divCustomers"></div>
<script type="text/javascript">
function callbackFunction(result, methodName)
{
var html = '<ul>';
for(var i = 0; i < result.length; i++)
{
html += '<li>' + result[i] + '</li>';
}
html += '</ul>';
document.getElementById('divCustomers').innerHTML = html;
}
</script>
<script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script>
</body>
</html>
访问测试结果如下:

安全问题
JSON劫持
详见WooYun-2012-11284,自己写了一个demo,大牛勿喷。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSON 劫持</title>
<script>
var info = {
"name":"admin",
"passwd":"123456"
};
function displayAuth(){
document.getElementById("name").innerHTML=info.name;
document.getElementById("passwd").innerHTML=info.passwd;
}
</script>
</head>
<body>
用户名: <span id="name"></span><br />
密码: <span id="passwd"></span><br />
<button type="button" onclick="displayAuth()">secret</button>
</body>
</html>
点击secret按钮,显示用户名和密码。
XSS漏洞
参考知道创宇给出的demo,访问http://127.0.0.1/getUsers.php?callback=<script>alert(/xss/)</script>即可触发。
<?php
//getUsers.php
$callback = $_GET['callback'];
print $callback.'({"id" : "1","name" : "知道创宇"});';
?>

防护
- 检查
Referer是否合法,因为请求是从攻击页面发起的,所以Referer是攻击页面的URL。 - 过滤
callback函数名及JSON里数据的输出。
绕过
空Referer绕过
开发者由于疏忽大意,忘记设置空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文件。
参考;
http://www.runoob.com/json/json-jsonp.html