我看不出 JSONP 中的回调函数与 AJAX 中的成功回调函数有何不同。
鉴于#1,我看不出它从根本上更安全。
那么唯一的区别是与 AJAX 的人工同域约束吗?
为什么 AJAX 不能只允许跨域请求;如果这会导致安全漏洞,那么攻击不只是 XSS 一个 JSONP 请求吗?
困惑,马克斯
我看不出 JSONP 中的回调函数与 AJAX 中的成功回调函数有何不同。
鉴于#1,我看不出它从根本上更安全。
那么唯一的区别是与 AJAX 的人工同域约束吗?
为什么 AJAX 不能只允许跨域请求;如果这会导致安全漏洞,那么攻击不只是 XSS 一个 JSONP 请求吗?
困惑,马克斯
ajax 调用是从客户端直接到服务器的实际 HTTP 请求。Ajax 调用可以是同步的(阻塞直到它们完成)或异步的。由于同源安全保护,只能对网页来自的同一服务器进行 ajax 调用,除非目标服务器明确允许使用 CORS 的跨源请求。
JSONP 调用是一个有趣的 hack,带有<script>
允许跨域通信的标签。在 JSONP 调用中,客户端创建一个脚本标记并在其上放置一个带有callback=xxxx
查询参数的 URL。该脚本请求(通过脚本标签插入)由浏览器发送到外部服务器。浏览器只是认为它正在请求一些 javascript 代码。然后,服务器为此调用创建一些特殊的 javascript,并且在该 javascript 返回时将由浏览器执行,服务器对在callback=xxxx
查询参数。通过定义变量或将数据传递给该函数,服务器可以将数据传回给客户端。对于 JSONP,客户端和服务器都必须在 JSONP 调用如何工作以及如何定义数据方面进行合作。客户端无法对不明确支持 JSONP 的服务器进行 JSONP 调用,因为必须由服务器构建正确类型的 JSONP 响应,否则它将无法工作。
因此,这两种通信方法的工作方式完全不同。只有 ajax 调用可以是同步的。根据<script>
标签插入的性质,JSONP 调用始终是异步的。
在 Ajax 调用中,响应在 ajax 事件处理程序中返回。
在 JSONP 调用中,响应会在返回的 Javascript 调用您的函数时出现。
在某些方面,JSONP 是一个绕过跨域安全机制的安全漏洞。但是,您只能调用明确选择支持类似 JSONP 机制的服务器,因此如果服务器不希望您能够调用它跨域,它可以通过不支持 JSONP 来阻止它。您不能对这些其他服务器进行定期 ajax 调用。
浏览器制造商无法真正关闭这个漏洞,因为如果他们这样做了,无数的网页会破坏已经使用 JSONP 或从其他域加载脚本的网页。例如,Web 上使用 Google 或 Microsoft CDN 之外的 jQuery 的每个页面都会中断,因为不允许浏览器从跨域域下载 javascript。
JSONP 主要是作为一种变通方法而发明的,以便能够发出跨域请求。但是,由于 JSONP 需要明确的服务器支持才能工作,所以这并不是真正的安全问题,因为只能对明确决定允许这种类型的跨源调用的服务器进行 JSONP 调用。JSONP 现在的使用比以前少得多,因为 CORS 被发明为一种更优雅的方式来控制/允许它。CORS 代表Cross Origin Resource Sharing,它为目标服务器提供了一种方法,可以准确地告诉 Web 浏览器允许哪些类型的跨源请求,甚至告诉它允许哪些网页域发出此类请求。它具有比 JSONP 更精细的控制功能,并且所有现代浏览器现在都支持 CORS。
这是一个跨域调用如何导致问题的示例。如果您可以从任何其他网页加载任意网页或进行任意 ajax 调用,那么想象您已经在其他浏览器窗口中登录到 Yahoo 上的 webmail 界面。这意味着您的 cookie 设置为允许来自浏览器的请求从雅虎获取数据。如果允许其他网页中的 javascript 向 Yahoo 发出 webmail 请求(这将自动附加您的 cookie),则它可以获取您所有的 webmail 数据并将其发送回它自己的站点。一个网站可以窃取任何其他网站的所有登录数据。所有的网络安全都会被破坏。
但是,按照我们今天的方式,只要 Yahoo 不支持使用相同 Web cookie 的 JSONP 接口,它就不会受到未经授权的 JSONP 请求的影响。
以下是关于跨域 ajax 的危险以及为什么必须防止它的其他一些很好的文章:
JSONP 的回调不是实际的回调。相反,JSONP 通过脚本注入工作。例如,如果你想进行 JSONP 调用,你可以将这个脚本元素插入到 DOM 中:
<script src="http://example.com/ajaxendpoint?jsonp=parseResponse"></script>
服务器的响应将是这样的:
parseResponse({"json":"value"});
它将在窗口的全局范围内进行评估。所以本质上 JSONP 就像一个远程exec()
的,服务器被告知要创建什么字符串来执行。
这与 Ajax非常不同:使用 JSONP,响应在脚本的全局范围内进行评估;使用 XMLHttpRequest,响应作为字符串接收,而不是评估。(此外,JSONP 只能与 GET 一起使用,而 AJAX 允许任何 http 方法。)
因此,对于您的第二个问题,“我看不出它从根本上如何更安全。” 嗯,你是对的,JSONP 实际上是非常不安全的。服务器可以返回任何它想要的脚本,并对你的浏览器做任何它想做的事情!
跨域请求是不安全的,因为它们可用于将有关当前页面的信息透露给另一个域上的页面。
你是对的,任何 XSS 攻击都可以使用 JSONP。CORS 的目的不是防止 XSS(如果您的页面上运行了不受信任的脚本,那么您无论如何都会被淹没)。
根本区别在于,出于某种原因,加载位于其他域(通过 script 标签)的 javascript 文件是完全可以的,但默认情况下加载其他跨域资源是不行的。
我同意你,因为这种划分似乎相当武断。在jQuery
中,当您执行 JSONP 调用时,实际上是在创建脚本标记、加载资源,然后 jQuery 库通过调用该 JSONP 结果中定义的函数来执行您的脚本。
在我看来,我想不出允许跨域 AJAX 引入的额外攻击向量,通过允许跨域脚本加载,它还没有扩大,这是到处使用的常见做法(googleCDN 的 jQuery,广告脚本,谷歌分析,和无数其他人)。
来自维基百科
In addition, many legacy cross-domain operations predating JavaScript are not subjected to same-origin checks; one such example is the ability to include scripts across domains, or submit POST forms.