浏览器中的CORS标头已更改,导致内容被阻止

时间:2019-03-07 08:04:53

标签: php ajax nginx cors

更新2(完整的日志集)

从客户的角度看

请求标头:

  

POST /dev/micro_server.php HTTP / 1.1   主持人:production-server.com
  连接:保持活动状态
  内容长度:86
  语法:无缓存
  缓存控制:无缓存
  接受:text / html, / ; q = 0.01
  来源:https://debug.dev
  用户代理:Mozilla / 5.0(X11; Linux x86_64)   AppleWebKit / 537.36(KHTML,例如Gecko)Chrome / 71.0.3578.98   Safari / 537.36 OPR / 58.0.3135.90
  内容类型:application / x-www-form-urlencoded; charset = UTF-8
  推荐人:https://debug.dev/
  接受编码:gzip,deflate,br
  接受语言:en-US,en; q = 0.9
  Cookie:debugger_session = iq4tbdk374mtvodsd3edcf2jq5

响应标头:

  

HTTP / 1.1 200确定
  伺服器:nginx / 1.4.6(Ubuntu)
  日期:2019年3月12日,星期二12:01:27 GMT
  内容类型:text / html
  传输编码:分块
  连接:保持活动状态
  X-Powered-By:PHP / 5.5.9-1ubuntu4.17
  访问控制允许方法:GET,POST,选项
  访问控制允许来源:https://production-server.com
  访问控制允许凭据:true
  过期:格林尼治标准时间1981年11月19日星期四08:52:00
  缓存控制:不存储,不缓存,必须重新验证,后检查= 0,预检查= 0
  语法:无缓存
  内容编码:gzip

控制台错误:

  

CORS策略已阻止从源“ https://production-server.com/dev/micro_server.php”访问“ https://debug.dev”处的XMLHttpRequest:“ Access-Control-Allow-Origin”标头的值为“ https://production-server.com” '不等于提供的原点。

控制台警告:

  

跨域读取阻止(CORB)阻止了MIME类型为text / html的跨域响应https://daikai.no/dev/micro_server.php。有关更多详细信息,请参见https://www.chromestatus.com/feature/5629709824032768

从服务器的角度来看

这是服务器说已接收和发送的内容(检查执行更新1记录的代码):

Array
(
    [req] => Array
        (
            ...
            [HTTP_ORIGIN] => https://debug.dev
            ...
        )

    [rsp] => Array
        (
            [0] => X-Powered-By: PHP/5.5.9-1ubuntu4.17
            [1] => Access-Control-Allow-Origin: https://debug.dev
            [2] => Access-Control-Allow-Methods: GET, POST, OPTIONS
            [3] => Access-Control-Allow-Credentials: true
        )

)

更新

我已经在服务器上添加了一些日志,脚本现在从以下几行开始:

# allow access from other domains
    header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
    header("Access-Control-Allow-Credentials: true");

$all = [
    'req' => $_SERVER,
    'rsp' => headers_list()
];

$s = print_r($all, true);
$p = '/var/www/path/to/file_' . uniqid() . '.txt';
file_put_contents($p, $s);

这样,我可以确认请求以正确的Origin到达服务器,并且服务器发送回正确的CORS标头。但是,开发者控制台中的Access-Control-Allow-Origin是错误的,请求已被阻止。

以下是通过上面的代码获得的精简日志:

Array
(
    [req] => Array
        (
            ...
            [HTTP_ORIGIN] => https://debug.dev
            ...
        )

    [rsp] => Array
        (
            [0] => X-Powered-By: PHP/5.5.9-1ubuntu4.17
            [1] => Access-Control-Allow-Origin: https://debug.dev
            [2] => Access-Control-Allow-Methods: GET, POST, OPTIONS
            [3] => Access-Control-Allow-Credentials: true
        )

)

问题

当收到的实际标头为Access-Control-Allow-Origin时,如何将https://production.com更改为Access-Control-Allow-Origin: https://debug.dev


(原始帖子)

背景

我有一个基于Web的调试工具,已将其安装在本地开发计算机上。在我的/ etc / hosts中,有一个条目已分配给域debug.dev。我还添加了本地CA机构,并已成功为域名创建了SSL证书,因此现在我可以在浏览器中打开https://debug.dev/,调试工具将正常打开。

该工具应与登台服务器和生产服务器一起使用。因此,它需要将AJAX请求发送到其他域。我对这些服务器拥有完全控制权,并且像这样从这些服务器发回CORS标头:

header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");

问题

现在,我面临着莫名其妙的局面,当我向生产服务器发送AJAX请求时,我得到了服务器域的错误 CORS标头:

  

Access-Control-Allow-Credentials:true
  访问控制允许来源:https://production-server.com

但是,如果我右键单击并使用在新标签页中打开,则CORS标头应为原标题;即

  

Access-Control-Allow-Credentials:true
  访问控制允许来源:https://debug.dev

据我所知,请求之间的唯一区别是,第一个请求是作为AJAX POST请求发送的,因此发送的是HTTP_X_REQUESTED_WITH标头,而第二个请求是作为普通的GET请求发送的。服务器如何返回不同的CORS标头?

2 个答案:

答案 0 :(得分:3)

问题可能类似于my answer here

  

服务器未配置为使用正确的“ Access-Control-Allow-”标头来响应OPTIONS请求。

在新标签页中打开网址是一个 GET 请求,并且正在运行,因为它满足要求时未发出预检请求simple request

定义为CORS documentation的条件

另一方面, ajax请求是一个 POST 请求,并且满足成为Preflighted request的条件,这意味着 preflight OPTIONS请求应该先做

简而言之,您已经正确设置了CORS响应标头,但是服务器未配置为添加这些标头用于OPTIONS方法请求

解决方案是使用 2xx响应处理服务器代码上的选项请求,并添加** Access-Control-Allow-就像您处理GET和POST请求一样。请记住,OPTIONS请求不包含任何参数,因此应在任何验证或请求解析之前完成。

此外,根据Access-Control-Allow-Origin documentation

  

如果服务器指定单个来源而不是通配符“ *”,则服务器还应在Vary响应标头中包含Origin -向客户端指示服务器响应将基于Origin请求标头的值而有所不同。

因此,还要设置 Var 响应标头:

例如在脚本顶部尝试:

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
    header("Access-Control-Allow-Credentials: true");
    header("Vary: Origin");
    exit;
}

参考

Preflighted requests

response for preflight 403 forbidden

答案 1 :(得分:1)

问题是您使用了header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);(顺便说一句,不建议这样做),并且标题错误。我打赌原因之一:

  • Web服务器将覆盖标头。
  • 浏览器使用缓存,尽管不应使用缓存。 (BFC)。
  • 您没有将更新的代码上传到请求服务器。

让我们从头开始。

  • 不相信自己,验证。 (我没看过一次,我们没有工作,然后又出现了我没有上传更改的反映:))。
  • 关闭浏览器调试器中的缓存。 (您必须具有打开的调试器)如果这是一个问题,并且该功能在池中可用,请向请求中添加时间戳。
  • 检查nginx / apache / server panel的配置

您是否知道您使用的构造与Access-Control-Allow-Origin: *是同义词?您应该检查HTTP_ORIGIN是否属于允许的池。