chrome中的跨域ajax POST

Posted

技术标签:

【中文标题】chrome中的跨域ajax POST【英文标题】:Cross domain ajax POST in chrome 【发布时间】:2011-08-21 18:48:22 【问题描述】:

关于跨域 AJAX 问题有几个主题。我一直在看这些,结论似乎是这样的:

除了使用 JSONP 之类的东西或代理解决方案之外,您应该无法对另一个域执行基本的 jquery $.post()

我的测试代码看起来像这样(在“http://myTestdomain.tld/path/file.html”上运行)

var myData = datum1 : "datum", datum2: "datum"
$.post("http://External-Ip:port", myData,function(return)alert(return););

当我尝试这个(我开始寻找的原因)时,chrome-console 告诉我:

XMLHttpRequest 无法加载 http://External-IP:port/page.php。起源 http://myTestdomain.tld 不允许 通过访问控制允许来源。

现在,据我所知,这是预期的。我不应该这样做。问题是 POST 实际上确实出现了低谷。我运行了一个简单的脚本,将$_POST 保存到一个文件中,很明显这篇文章已经过时了。我返回的任何真实数据都不会传递到我的调用脚本,由于访问控制问题,这似乎又是预期的。但是帖子实际上到达服务器的事实让我感到困惑。

我假设在“myTestdomain”上运行的上述代码不能对另一个域(外部IP)执行简单的$.post() 是否正确? 是否期望请求实际上会到达外部 IP 的脚本,即使没有收到输出?或者这是一个错误。 (我使用的是 Chrome 11.0.696.60)

【问题讨论】:

这意味着它确实可以防止(某些)XSS 攻击,但不能防止 CSRF?反正让我觉得很奇怪:P 我根据 Michiels 的回答撤回了我的评论,这在安全方面确实有意义。 你可以试试这个CHROME EXTENTION 【参考方案1】:

我早些时候在 WebKit bugtracker 上发布了一张关于此问题的票,因为我认为这是一种奇怪的行为并且可能存在安全风险。

由于与安全相关的票证无法公开查看,我将在此处引用 Justin Schuh 的回复:

这完全按照规范的要求实现。对于简单的跨域请求 http://www.w3.org/TR/cors/#simple-method> 没有飞行前检查;如果相应的标头未授权请求来源,则发出请求并且无法读取响应。从功能上讲,这与创建表单并使用脚本进行异地 POST 没有什么不同(这一直是可能的)。

所以:您可以进行 POST,因为无论如何您都可以通过嵌入表单并使用 javascript 触发提交按钮来完成此操作,但您看不到结果。因为在表单场景中您无法做到这一点。

一种解决方案是向目标服务器上运行的脚本添加标头,例如

<?php
header("Access-Control-Allow-Origin: http://your_source_domain");
....
?>

尚未对此进行测试,但根据规范,应该可以。

Firefox 3.6 似乎以不同的方式处理它,首先执行一个 OPTIONS 以查看它是否可以执行实际的 POST。 Firefox 4 和 Chrome 一样,或者至少在我的快速实验中是这样。更多信息请访问https://developer.mozilla.org/en/http_access_control

【讨论】:

所以这意味着虽然(根据 Justin Schuh 的回答)您应该能够发布该帖子似乎是合乎逻辑的,但不能保证,因为某些浏览器(在您的示例中为 Firefox)实际上不不让你这样做。 我之前尝试过使用 FF 3.6,但它并没有让我这样做(而是使用了 OPTIONS)。刚才我尝试使用 确实 允许请求的 FF 4.0(以与 Chrome/Safari 相同的方式,不允许您查看结果)。 @Nanne @Michiel 您看到的 OPTIONS 请求是因为预检 - 如果您使用自定义标头或内容类型设置为 application/x-www-form-urlencoded, multipart/form-data 或 @987654324 以外的其他内容进行 POST 请求@,浏览器尝试通过在发出实际 POST 请求之前发出 OPTIONS 请求来确保允许带有这些标头的请求。【参考方案2】:

关于 JavaScript same-origin policy 限制需要注意的重要一点是,它是现代浏览器为了安全而内置的东西 - 它不是技术限制或服务器强制执行的东西。

回答你的问题,这些都不是错误。

请求不会停止到达服务器 - 这使服务器可以选择通过设置适当的标头来允许这些跨域请求1

浏览器也会收到响应。在使用访问控制标头 1 之前,对跨域请求的响应将被具有安全意识的浏览器阻止在其轨道上 - 浏览器会收到响应但不会发送它关闭脚本。使用访问控制标头,服务器可以选择设置适当的标头,向兼容的浏览器表明它希望允许某些原始 URL 进行跨域请求。

响应的确切行为可能因浏览器而异 - 我现在无法确定,但我认为 Chrome 在使用 jQuery 的 ajax() 时调用了 success 回调函数,但响应为空。 IIRC,Firefox 不会调用 success 函数。

【讨论】:

嗯,我很困惑。将标题设置为“不允许”有什么用,但仍然运行脚本?这意味着我可以做我的帖子(这很好),尽管同源策略阻止我像处理同域请求一样处理它。我错过了什么吗? @Nanne 您的 JavaScript 将被允许执行并发出请求 - 请求将通过服务器,但您的 JS 可能会或可能不会收到响应。如果服务器设置了允许该域(源)发出跨域请求的标头,则支持访问控制标头的较新浏览器将使响应通过您的 JS。如果浏览器不理解这种允许 CDR 的机制,或者服务器没有设置允许该来源的标头,那么您的 JS 将不会得到响应。这有助于澄清吗?【参考方案3】:

我也遇到了同样的事情。您可以跨域发帖,但无法收到回复。这就是我期望在 Firefox、Chrome 和 IE 中能够做到的事情并发生在我身上。

绕过这个警告的一种方法是拥有一个本地 php 文件,该文件将通过 curl 调用数据并响应您的 javascript 响应。 (有点重述了你所说的你已经知道的内容。)

【讨论】:

为什么会出现这种行为?如果标头设置为请求无效,我有点希望脚本本身不会运行。像:设置标题“不允许”,然后发送一些否定/错误的东西。但显然这不会发生:) 我已使用此功能发送数据,例如到不同系统的链接。此链接用于将文件下载到单独的服务器,但不需要对脚本作出响应。我注意到的奇怪的事情是,返回的标头具有正确的内容长度,但它只是去掉了数据。我希望它会一起阻止它,所以我什至看不到标题响应。 是的,这正是我所看到的。不过没想到:)【参考方案4】:

    是的,这是正确的,除非您使用任何代理,否则您将无法做到这一点。

    不,一旦有这样的限制,请求就不会去外部IP。

【讨论】:

虽然有一个针对 FireFox 的 hack,我曾经试图克服这个问题以进行测试。我也找到了适用于 Chrome 的解决方案,但从未奏效。 嗯,这意味着第 2 点是一个错误,因为我可以确认它确实到达了 IP。 您在 #2 上是不正确的,因为这是允许的 - 否则诸如访问控制标头(链接到我的答案)之类的解决方案将不起作用。跨域限制是“人为的”,因为它们是作为安全措施添加到浏览器中的,而不是因为固有的无法发出此类请求。因此,请求和响应都会出现在网络上,只是您的 JS 代码不会看到响应,因为浏览器会阻止它。 那我的错。我使用常识

以上是关于chrome中的跨域ajax POST的主要内容,如果未能解决你的问题,请参考以下文章

Internet Explorer 中的跨域 POST 请求 ajax

Chrome 中的跨域问题可能是奇怪的 Dart HttpRequest 行为的 b/c

chrome下如何实现ajax的跨域访问

Jquery:使用 laravel 的跨域 ajax 'POST'

Ajax的跨域问题(包括解决方案)?

逆向工程使用 Ext.Ajax.request 的跨域 POST 请求