IFRAME 沙盒属性正在阻止 AJAX 调用
Posted
技术标签:
【中文标题】IFRAME 沙盒属性正在阻止 AJAX 调用【英文标题】:IFRAME sandbox attribute is blocking AJAX calls 【发布时间】:2013-01-07 07:55:59 【问题描述】:我有一个应用程序 (http://localhost/MyApp
),其中一些部分是通过 IFRAMES 呈现的。这些 iframed 部分与应用程序的 DOM 的其余部分无关,因此我应用了 sandbox
属性。
IFRAME 是这样声明的:
<iframe src="/MyApp/en/html/action?id=1" sandbox="allow-forms allow-scripts" seamless="seamless"></iframe>
iframed 页面有一个按钮,可以对同一个 Web 应用程序进行 AJAX 调用,但浏览器发出的不是HTTP GET
,而是显示为Cancelled
的HTTP OPTIONS
,然后发生错误:
XMLHttpRequest cannot load http://localhost/MyApp/en/data/action?id=1. Cannot make any requests from null.
Ajax State 0 Error: HTTP 0
如果我将allow-same-origin
添加到sandbox
属性,它可以工作。就I read here 而言,它不应该影响AJAX 调用。
为什么会这样?是否将路径 /MyApp/en/html/action
视为整个 IFRAME 的来源并阻止请求到先前级别?
干杯。
【问题讨论】:
看看这篇html5rocks.com/en/tutorials/security/sandboxed-iframes 文章。这是对沙盒属性的一个很好的解释。 【参考方案1】:它影响 Ajax 的原因是因为 Ajax 受 Same Origin Policy 规则管理,当您对它进行沙箱处理时,您实际上是在告诉浏览器将 iframe
内容视为来自不同的来源。引用同一个article:
独特的来源处理。 所有内容都在独特的来源下进行处理。内容无法遍历 DOM 或读取 cookie 信息。这意味着即使来自同一个域的内容也会被跨域策略处理,因为每个 IFRAME 内容都将被视为一个唯一的来源。
嵌入的内容只允许显示信息。IFRAME 内不能进行任何可能危及托管网站或利用用户信任的操作。
换句话说,如果您在sandbox
属性中省略allow-same-origin
,它会将沙盒页面视为属于不同的域(实际上,它将视为具有null
来源)。由于向null
发出Ajax 请求没有意义,沙盒页面根本无法进行Ajax 调用(如果允许向localhost
发出Ajax 请求,它们将与来自父页面的调用无法区分,从而违背了目的沙盒)。
附加信息
如果您尝试对不同的域进行 Ajax 调用,显然会失败:
<script src="http://code.jquery.com/jquery.min.js"></script>
<script>
console.log(location.host);
$.post('https://google.com/',,function() );
</script>
但是,如何失败将取决于所使用的沙盒属性。如果您将上面的页面嵌入到带有allow-same-origin
的iframe
中,它将打印到控制台:
localhost
XMLHttpRequest cannot load https://google.com/. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
...如果你嵌入它没有 allow-same-origin
:
localhost
XMLHttpRequest cannot load https://google.com/. Cannot make any requests from null.
请注意,虽然两者都将location.host
报告为localhost
,但一个认为来源是http://localhost
,而另一个认为它是null
(显示您在示例中遇到的相同错误消息)。
推理
为什么阻止来自同一域的沙盒内容的 Ajax 调用如此重要?如文章中所述:
同一域上的内容应该是安全的,这是有道理的。这里的风险主要源于用户生成的内容被重新托管在 IFRAME 中。
让我们举个例子:假设 Facebook 决定允许用户在他们的页面中发布小的 HTML5 动画。它将它们存储在自己的服务器中,并在显示时将它们沙箱化为allow-scripts
(因为动画需要脚本才能工作)但拒绝其他所有内容(特别是allow-same-origin
,因为你不想要用户代码弄乱了父页面)。如果 Ajax 调用默认不被阻止会发生什么?
Mallory 创建了一个“动画”,其中包括:
使用 Facebook 的 API(例如,Open Graph)对 Facebook 执行 Ajax 调用;服务器会很乐意接受调用,因为它知道请求来自以https://facebook.com
为来源的页面。
创建一个指向她自己的服务器的URI,返回数据为查询字符串,并将其设置为沙盒页面中图片的src
。
当 Alice 访问 Mallory 个人资料并看到动画时,上面的脚本运行:
Ajax 调用在 Alice 的浏览器中运行,而 Alice 已登录;由于服务器不知道调用来自何处(主页或嵌入页面),因此它会执行任何请求 - 包括检索个人信息。
当使用 Mallory 的 URI 创建 img
元素时,浏览器将尝试正常加载“图像”,因为图像不受同源策略的约束。
由于 URI 在查询字符串中包含 Alice 的私人信息,Mallory 的服务器可以保存它并返回它想要的任何图像。现在,马洛里有了爱丽丝的个人信息,爱丽丝没有任何怀疑。
【讨论】:
所以你的意思是因为父框架正在使用主机A,即使子框架也使用主机A作为原点,它也无法对自己的原点执行AJAX,因为父框架正在使用它?这听起来像是一个古怪的实现,浏览器应该知道每个 iframe 执行的是哪些调用。 浏览器可以,但是服务器呢?如果服务器没有明确授予沙盒页面同源权限,你怎么知道它期望从它接收 Ajax 调用?如果您的服务器是cajoling server,而iframe
中运行的代码来自不受信任的第三方怎么办?它们运行的域将是相同的,但这并不意味着第三方代码应该能够对服务器进行 Ajax 调用(可能会泄露敏感信息)。恕我直言,这是正确的设计,安全方面。
服务器不应该关心请求来自哪里。实际上阻止请求的是浏览器而不是服务器。抱歉,我觉得这个问题有点奇怪。
请查看我更新的答案。沙盒的全部意义在于拒绝所有未明确允许的内容。由于浏览器不知道服务器关心什么和不关心什么,它应该在安全方面犯错,并假设 Ajax 调用(以及其他同源权限)不可以。如果您想从沙盒内容中接受 Ajax,但又不让它与父页面混淆,恐怕您需要另一种策略,例如 postMessage 或 CORS。
我想指出,将allow-same-origin 标签添加到沙盒属性实际上不会使外部来源被视为同一个来源。它只会让浏览器处理这个 iframe,因为普通的 iframe 将由同源策略处理。因此,如果您将此属性应用于外部域页面,它仍然无法访问您的主页的 DOM。仅当您将其应用于同一域(或域策略标头允许的任何其他域)上的 url 时,该页面才能访问您的 DOM 或向您的域发出 AJAX 请求。以上是关于IFRAME 沙盒属性正在阻止 AJAX 调用的主要内容,如果未能解决你的问题,请参考以下文章
由具有沙盒属性的 <iframe> 发出的 XHR 请求的原始标头为空
Chrome 控制台中的沙盒权限错误,但我没有使用任何 iframe