JSONP原理 JSONP(JSON with Padding)是一种跨域获取数据的方法,因为带src
属性的标签如<script>
允许跨域(1. 在CSP没有设置的情况下, 2.跨域时是可以带cookie的),因此前端可以设置一个callback请求并生成一个访问后台某个<script>
的链接,后台在链接中动态的将数据包裹在先前的callback函数中,作为参数返回给前台,这样就完成了跨域获取数据的效果。
简单示例 后台 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import jsonfrom flask import Flask, request, render_template_stringapp = Flask(__name__) app.secret_key='random_secret_key' @app.route('/remote.js', methods=['GET']) def remote () : _id=int(request.args.get("id" )) user=[ dict(username="zhangsan" ,stat="student" ), dict(username="lisi" ,stat="working" ), dict(username="wangwu" ,stat="student" ), ] callback=request.args.get("callback" ) json_data=json.dumps(user[_id]) template="{{callback}}({{json_data}})" return render_template_string(template, callback=callback, json_data=json_data) if __name__ == '__main__' : app.run(host='127.0.0.1' , port=8888 , debug=True )
这样,加入我们访问http://127.0.0.1:8888/remote.js?id=1&callback=mycallback,那么会得到如下结果:
前台 那么前端就可以嵌入一个<script>
标签,其中src
设置为http://127.0.0.1:8888/remote.js?id=1&callback=mycallback,以此获取数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <html xmlns ="http://www.w3.org/1999/xhtml" > <head > <title > </title > <script type ="text/javascript" > var mycallback = function (data ) { alert('username: ' + data.username + ', status: ' + data.stat); }; </script > <script src ="http://127.0.0.1:8888/remote.js?id=1&callback=mycallback" > </script > </head > <body > </body >
可以看到获取数据成功:
同时给出jQuery的版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $(document ).ready(function ( ) { $.ajax({ type: "get" , async : false , url: "http://127.0.0.1:8888/remote.js?id=1" , dataType: "jsonp" , jsonp: "callback" , jsonpCallback:"mycallback" , success: function (json ) { alert('username: ' + data.username + ', status: ' + data.stat); }, error: function ( ) { alert('fail' ); } }); });
JSONP的安全性问题 JSON劫持导致CSRF 主要表现为后台没有做身份认证,导致任何前台都可以发送JSONP请求,若请求中存在敏感信息则会发生信息泄露(相当于CSRF)。
防御方法
使用referer过滤,对于空referer不予以放行
增加一个随机token
可以看到整体的防御方法类似于CSRF的防御方法。
空referer 进行基于referer的防御时,对于空referer的情况应不予以放行,因为攻击者可以使用某些标签(iframe
)构造空referer。Payload如下:
1 <iframe src ="javascript:'<script>function callback(o){alert(o.username);}</script><script src=http://127.0.0.1:8888/remote.js?id=1&callback=callback></script>'" > </iframe >
自定义Callback导致XSS 比如说本文的实例,攻击者可以构造如下链接导致反射型XSS:
1 http://127.0.0.1:8888/remote.js?id=1&callback=<script>alert(/xss/)</script>
防御方法
定义Content-Type: application/json
对XSS字符进行能过滤