【问题标题】:I don't get how JSONP is ANY different from AJAX我不明白 JSONP 与 AJAX 有何不同
【发布时间】:2012-05-04 14:38:52
【问题描述】:
  1. 我看不出 JSONP 中的回调函数与 AJAX 中的成功回调函数有何不同。

  2. 鉴于 #1,我看不出它从根本上更安全。

  3. 那么唯一的区别是与 AJAX 的人为同域约束吗?

  4. 为什么 AJAX 不能只允许跨域请求;如果这会导致安全漏洞,那么攻击不会只是 XSS 一个 JSONP 请求吗?

困惑, 最大

【问题讨论】:

    标签: javascript jsonp


    【解决方案1】:

    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 的危险以及为什么必须防止它的其他一些很好的文章:

    Why the cross-domain Ajax is a security concern?

    Why Cross-Domain AJAX call is not allowed?

    Why are cross-domain AJAX requests labelled as a "security risk"?

    【讨论】:

    • 感谢您的回复。但我有几个关于你的回答的问题。首先,当您说“ajax 调用是一个实际的 HTTP 请求”时,您是在暗示 JSONP 不是吗?其次,我不明白为什么 JSONP 服务器响应必须是函数调用,因为如果它可以进行函数调用,那么它必须能够进行任何类型的语句。第三,我一直认为
    • @Max - JSONP 脚本标签注入是间接 HTTP 请求。当您动态注入脚本标签以发起 JSONP 请求时,它会间接导致浏览器针对特定脚本 URL 发出 GET 请求。与 ajax 调用不同,您的应用程序中不会有任何代码“监听”ajax 调用的响应,并且可以看到整个响应,包括 HTTP 标头等……相反,当服务器响应时,浏览器期望响应是 javascript,它将解析和执行。是的,javascript 可以是服务器想要的任何东西,它可以做任何事情。
    • @Max - 但是要让网页中的代码使用响应,它必须以某种方式与网页中的代码配合。该合作的标准约定是 callback=xxx 查询参数。也可以发明其他约定。但是,您确实允许其他服务器将 javascript 注入您的页面,因此您显然只会对您信任的服务器进行 JSONP 调用。
    • @Max - 注入的脚本标签始终是异步的 - 它们的工作方式与页面 HTML 中的脚本标签不同。
    • 感谢 jfriend00 的回复。现在一切都说得通了!
    【解决方案2】:

    根本的区别在于,出于某种原因,加载位于其他域的 javascript 文件(通过 script 标签)是完全可以的,但默认情况下加载其他跨域资源是不行的。

    我同意你的看法,因为这种划分似乎相当武断。在jQuery 中,当您执行 JSONP 调用时,实际上是在创建脚本标记、加载资源,然后 jQuery 库通过调用该 JSONP 结果中定义的函数来执行您的脚本。

    在我看来,我想不出通过允许跨域 AJAX 引入的额外攻击向量,通过允许跨域脚本加载,它还没有扩大,这是到处使用的常见做法(googleCDN 的 jQuery,广告脚本,谷歌分析,以及无数其他)。

    来自wikipedia

    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.

    【讨论】:

    • 感谢您的回复。但如果是这样的话,浏览器不应该简单地删除原点约束吗?它不会降低安全性,只会使开发更容易、更一致。
    • @Max 和 Nucleon - 阅读我回答的最后两段(我刚刚添加完毕),其中描述了跨域 ajax 调用的一个主要问题。
    • @jfriend00 在 CSRF 上的 bobnice 回答说服了我。感谢您发布链接!
    【解决方案3】:

    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(如果您的页面上运行了不受信任的脚本,那么您无论如何都会被淹没)。

    【讨论】:

      猜你喜欢
      • 2019-06-21
      • 2011-08-21
      • 2022-06-30
      • 2019-07-14
      • 2015-08-06
      • 1970-01-01
      • 2021-05-13
      • 2011-02-17
      • 1970-01-01
      相关资源
      最近更新 更多