使用过JSONP跨域请求的都知道,JSONP就是发送一个请求从服务端返回一个JS函数,在WEB页面也定义一个相同函数,这样请求完毕后就可以执行JS了,
这样虽然很容易实现跨域交互,但是有一个弊端就是无法保证安全性,下面是我在一个博客中看到的解决方法,分享一下
从一个经典的跨域脚本应用说起:
JSONP 是一个流行的跨域获取数据的方案,它原理是向文档动态插入一个 script 标签,向远程服务器发起一个脚本请求,然后远程服务器返回一个定的回调函数并传入 JSON 数据,这样完成跨域数据交换。
如页面预先定义一个全局函数:window.jsonp534533 = function (json) { //... }
向服务器发起 script 请求 JSONP
http://api.douban.com/jsonp?key=3435&type=music&callback=jsonp534533
服务器返回 js 文件
jsonp534533({ "code": 0 "data": [...]})
JSONP 虽然很方便实现前端跨域,但是其弊端也是显而易见的:无法保证安全性。
由于是 script 直接执行,假若提供 JSONP 服务器返回了恶意代码 (如被黑客入侵),这样将会十分危险。恶意代码可以向页面插入广告或者直接重定向第三方站点、甚至可以窃取 cookie 用 N 种方式发送到第三方服务器,这些都直接威胁站点安全。
有没有一种纯前端的方案可以安全的加载 JSONP 呢?下面是我想到的一个方案:
javascript 沙箱
一个安全的 JSONP 脚本它只给回调函数传入数据而不应该读写 document,更严格一点是不能进行任何的 DOM 与 BOM 操作。基于此,我们可以利用空白 iframe 新建一个脚本执行环境,然后限制 iframe.contentWindow 的 DOM 与 BOM 方法,让这个环境中运行的脚本无法读写主页面,也无法发起任何通讯请求,包括 AJAX 方式 与 new Image() 、 script 方式等,与 这样理论上实现了一个 javascript 沙箱环境。
由于浏览器 DOM 与 BOM 实现机制不同,我们可以结合以下两种方式编码。
一、覆盖不安全的方法与属性
- this.__proto__ = {} (现代浏览器)
- 设置全局同名函数(IE为主)
- 向文档插入一个同名 name 属性的 iframe (针对opera)
二、使用 HTML5 iframe “sandbox” 属性
HTML5 iframe “sandbox” 属性可以限制 iframe 内容的权限。这个属性目前只有 chrome 、 safari 、IE10 支持,而且这个属性可选项太少,虽然能够限制 ajax 请求,但无法阻止传统的跨域请求,如 new Image 或者 script 方式。
javascript 沙箱应用场景畅想
除了安全加载 JSONP 之外,沙箱机制还可以为社交平台实现安全 javascript API 提供可能:
由于安全问题,社交平台第三方 APP 大多以 iframe 形式载入,但是由于 iframe 本身的问题,这样体验远远不能达到“原生”应用的高度。针对此我们可以给 APP 开发者设计一个应用 API,让其只能在沙箱环境中操作 APP 自身的 DOM 与有限的公用 API,而没有访问全局对象的能力,从而实现体验与安全完美合一。
scriptSandbox 项目
scriptSandbox 是上述想法而创建了一个开源项目,正如本文所述,它实现了沙箱环境用来隔离 JSONP 可能出现的危险操作。目前你也可以理解它是一个 JSONP 安全加载器,scriptSandbox 项目主页:
特别说明:下载包中含有测试脚本 test.js, 它除了传递 JSONP 外,还模拟了 “危险” DOM 操作,你可以在不同浏览器中测试沙箱隔离能力。欢迎您在 test.js 写“危险”代码对沙箱进行攻击,若实现下面要求均算成功成功:
- 获取页面 document 访问能力
- 获取与服务器通讯能力
- 弹出对话框干扰用户
欢迎您给我提交漏洞报告 1987.tangbin(a)gmail.com
参考文档:
原文地址
另外推荐一个也比较强大的跨域操作插件,一般我都用这个在博客园搜索sjax就有了