定义更安全的JSONP

说明

  • 本文翻译自这篇文章
  • 文中并未就JSOPN提出更加安全的一个定义,但是为跨域访问策略的发展指明了一个方向;

引言

  • JSON是一种轻量级的数据交换格式。它是由Douglas Crockford正式提出的规范。JSON作为在两个实体间进行数据传输的强大工具的代表,无论发收数据的实体采用的是什么计算机语言,JSON已经被越来越多的接受和使用。

跨域访问的AJAX–简介

  • 浏览器的同源策略决定了,在数据传输时,如果目标资源所在的域等同于发出请求的页面,这样的传输行为才被允许。这一措施被所有的现代浏览器所采用,以防止不必要的或不安全的恶意JavaScript的用户行为。
  • 跨域Ajax是指突破同源策略的限制,使得跨域请求成为可能的想法。事实上,跨域的Ajax不是绝对的不安全或邪恶的,它实际上是许多世界上最流行和实用的应用中必不可少的。但是,由于种种原因,跨域Ajax始终和同源策略格格不入。

JSON-P (JSONP)

  • JSONP是这样的一个机制,它可以通过<script>标签请求不同域的内容。 2005年12月,Bob Ippolito正式提出JSONP(后来被称为JSON-P或JSON-with-padding),以此来充分利用的<script>标签的属性,实现跨域请求JSON格式的数据。JSON-P的工作原理是使一个<script>元素(HTML标签或通过JavaScript插入到DOM中),它请求服务器端的数据服务。HTTP请求的响应(装“的JavaScript”的实体内容)的内容是在请求中预先定义的,它通过参数传递给服务器端,提供被请求的JSON格式的数据的名称。当脚本执行时,相应的函数被调用,回传JSON格式的数据,从而使请求页面接收和处理这些数据。例子如下:
1
2
3
function handle_data(data) {
// `data` is now the object representation of the JSON data
}
1
2
3
http://some.tld/web/service?callback=handle_data:

handle_data({"data_1": "hello world", "data_2": ["the","sun","is","shining"]});
  • 正如你所看到的,远端Web服务通过请求URL中的参数知道调用的函数的名称。只要该函数是在请求页面实际定义的,它会在收到数据后被调用。

问题

  • 迄今,JSON-P基本上已经被会议非正式的定义,事实上,浏览器可以接受任意的JavaScript响应。这意味着,任何依靠JSON-P的实现跨域访问的策略其实都将带来同源策略试图避免的危害。例如,一个恶意的Web服务可以通过调用函数发送JSONP请求,黑客可以通过返回的JavaScript信息窃取用户的隐私数据等。
  • 出于这个原因,很多人将JSON-P视为一种不安全和易被黑客利用的跨域Ajax策略,这似乎理由非常充分。所以,程序员们必须足够用心,在调用远程Web服务之前必须确认对方是受控或受信任的,这样才能避免他们的用户受到伤害。

替代方案

  • 有很多替代JSON-P实现跨域请求的办法,但每种方案都有自己的缺点和面临的挑战。这些技术将不会在这里详细介绍,除了这个:CORS(跨域资源共享)。 这是最近最流行的的JavaScript跨域Ajax调用方案之一。简单地说,CORS是一种扩展的XMLHttpRequest(又名“XHR”)对象,它可以让浏览器进行跨域调用(尽管存在同源策略的限制)。它会首先“预检测”目标服务器,确认服务器允许它这样做。
  • 换句话说,远程服务器能够选择加入或退出此类通信,基于它认为是否是合适的。例如,一台服务器可以应答用户端的Ajax请求,并从唯一认可的网站域名的一个预先定义的列表中获取一些内容回传客户端,而且拒绝任何其他页面中的所有其他请求。或者,如果服务器认为适合这样做,它可以开放其内容被任何其它域进行检索。
  • 乍一看,CORS可能看起来像是跨域Ajax请求的理想解决方案,使“黑客”无从下手。Nicholas Zakas最近写了一篇关于CORS的跨域Ajax请求方案,并指出它是浏览器跨域Ajax请求的解决方案中最有希望的一个。
  • CORS是否将最终成为浏览器跨域访问解决方案的标准,我们将拭目以待。当然它也有一些缺点,很可能存在一些细节问题(devil is always in the details)。
  • 首先,CORS需要实现一个Web服务,以实现拦截HTTP请求头中特殊的“预检”的授权请求,并根据服务器相关的策略,决定响应的格式。如果一个基于JSON格式的网络服务需要JSON-P跨域请求的支持,这相当简单,只需在一个函数调用中包装JSON数据块即可。
  • 在所有的互联网Web服务实现回传自定义数据更加值得期待,当然这取决于Web服务器软件的权限设置。这种技术可能需要若干年才能流行开来,并实现大部分的网络服务供应商兼容CORS。截至目前,这是非常新的技术,很少Web服务已经这样做了。
  • 此外,CORS仅在IE8浏览器开始实施(尽管有一些轻微的语法上的不同),尚未兼容Opera。因此,不支持CORS的情况时有发生,这意味着替代跨域Ajax的备选方案也许在1-3年后才可能推广开来。

可能的解决方案

  • 现在,JSON-P是跨域Ajax一个可行的解决方案。CORS可以减少黑客攻击的可能性,它可能应该在JSON-P技术串联部署,从而在不支持CORS的浏览器推广开来。然而,JSON-P的安全问题应当认真考虑并加以解决。
  • 所以,JSON-P严格的子集的定义是非常必要的。下面我们将介绍什么应视为有效、安全、可被允许的JSON-P。
1
2
3
4
5
functionName({JSON});

obj.functionName({JSON});

obj["function-name"]({JSON});
  • 其含义是,只能有一个函数表达式(函数的引用,或对象属性的引用)可用于作为该函数的JSON-P的响应,在这个单一的()中一定是严格有效的、可解析JSON对象。函数调用可以选择性地跟着一个分号。
  • 该提案的最关键的部分是浏览器厂商必须开始强制将这条规则应用于接收JSON-P回传数据的的<script>脚本上,并对任何不符合JSONP内容的错误抛出异常(或至少停止处理)。
  • 为了使浏览器能够知道什么时候应该过滤内容,或是看作是常规的JavaScript内容,MIME类型为“application / JSON-P”和/或“text/ JSON-P”的必须请求<script>标签中声明。

缺点

  • 不支持CORS的浏览器以及将来也不支持CORS的浏览器将不会拥有JSON-P的严格保护,这意味着,使用这些浏览器的用户将不会得到保护。但是,目前所有的浏览器都可以增加这个内容过滤功能,这对于使用尚未兼容CORS的浏览器的用户是一种安全支持。

注解

  • 一个可能的帮助老的浏览器用户安全的利用JSON-P技术的方案是提前检测浏览器没有这样的支持,并只对那些在不安全的浏览器中的、有条件的连接发出的请求启用本地服务器代理,它可以作为一个网关,并根据上面提到的逻辑进行内容过滤。

前瞻

  • 这是第一次讨论安全的JSON-P。在此,我主张在社区开放讨论,共同寻找可以向W3C,WHATWG和浏览器厂商宣传的一个可行的定义。
  • 最好方法是回复本文,或从本讨论建立链接。此外,本网站代码已经托管在GitHub上,你可以fork或修改以便继续讨论,然后通过pull操作更新讨论。最后,你可以在下面的评论表中作简短评论,但请保持简短,以便他人跟踪讨论进度。
您的支持是对我最大的鼓励!