CORS保护:HTTP_ORIGIN的重点是什么

时间:2017-06-14 02:02:45

标签: javascript php ajax http-headers cors

我目前正在为所有域(scripts.domain.com)开发一个中央AJAX脚本库。

我有以下PHP代码,理论上可以很好地防止错误的CORS请求。

$valid_cors = array("domain1","domain2","domain3");
if(in_array($_SERVER['HTTP_ORIGIN'],"https://".$valid_cors)) {
    header('Access-Control-Allow-Origin: https://{$valid_cors}', false);
    header("Access-Control-Allow-Methods: GET, POST, PUT");
    header("Access-Control-Allow-Headers: Content-Type");
}

我打赌你可以在你阅读之前猜到我收到的信息。对于那些无法做到的人来说,这就是:

  

XMLHttpRequest无法加载   https://scripts.domain.com/scripts/ajax_caller.json?   No' Access-Control-Allow-Origin'标题出现在请求的上   资源。起源' https://domain1'因此是不允许的   访问。

在这里阅读了一些问题之后,我的理解是大多数浏览器甚至都不发送HTTP_ORIGIN标题,所以基本上整个ACAO系统都是毫无意义的,因为你必须放弃Allow - 打印为星号,允许多个域调用它。您也不能放置多个A-O标头,因为如果有多个A-O标头,浏览器会完全阻止该请求。

我们现在都知道 - 不要相信任何浏览器发送给你的东西,因为它很容易被伪造,所以为什么这甚至被认为是实现的呢?

使用星号系统对我没有任何好处,因为我们检查了CSRF&在调用任何操作文件之前执行会话,但是对于大多数用户来说,这可能会带来更多的弊大于利,从而使他们陷入虚假的安全感。

拜托,有人可以告诉我,我在这里得到了错误的结论并且我使用它错了吗?似乎没有多少人可以给出答案栏星号,这让我更加确信这是唯一的方法。

2 个答案:

答案 0 :(得分:5)

  

在这里阅读了一些问题之后,据我所知,大多数浏览器甚至都不发送HTTP_ORIGIN标题

嗯,那不是真的。任何支持CORS的东西都支持发送Origin请求标题。

  

因为你必须把Allow-Origin作为星号,以允许多个域来调用它

不,那也不是真的。您的服务器可以根据不同的来源做出不同的响应。

例如,如果请求包含Origin: a.example.com,则您可以使用Access-Control-Allow-Origin: a.example.com进行回复。

如果Origin: b.example.com发出请求,请回复Access-Control-Allow-Origin: b.example.com

  

我们现在都知道 - 不要相信任何浏览器发送给你的东西,因为它很容易被伪造,所以为什么这甚至被认为是实现的呢?

CORS不用于保护服务器资源。这是为了隔离客户端访问。

如您所知,网页可以包含来自多个来源的数据。我们一直使用图像,脚本等来执行此操作。但是,这只允许我们查看来自多个来源的内容。它不允许来自多个来源的脚本看到彼此的数据。

假设情况并非如此......并且您可以制作跨域AJAX请求。假设我有一个关于投资建议的热门博客。我知道读我博客的人最近也可能登录了他们的经纪网站。我可以在我的博客网站上安装一个脚本,该脚本会向经纪网站发出AJAX请求以进行交易。原因是,而不是用户发出请求,现在我正在提出请求......但是使用他们的cookie。我甚至不知道他们会冒充他们!可怕的东西。

在一个更常见的示例中,许多家庭路由器都有具有默认凭据的管理面板。很多这些路由器也没有使用正确的HTTP动词...所以GET请求可以用来做开放端口之类的事情。这些路由器仍然注定失败,因为我可以使用简单的图像标记发出GET请求。像这样:

<img src="http://192.168.1.1/firewall/?action=openPort&port=22" />

(当然“图像”无法加载,但浏览器会发出请求,路由器也会遵守它。)

如果路由器使用了PUTPOST等正确的动词,则无法使用简单的图像标记进行此更改。但是如果没有CORS,页面可以使用PUTPOST发出AJAX请求,在您不知情的情况下控制您的家庭路由器!基本上,使用您的计算机作为运行特权脚本的地方。

以这种方式防止对资源的跨源访问有助于保护您的特权访问安全。

答案 1 :(得分:0)

  

我有以下PHP代码[...]

$valid_cors = array("domain1","domain2","domain3");
if(in_array($_SERVER['HTTP_ORIGIN'],"https://".$valid_cors)) {
    header('Access-Control-Allow-Origin: https://{$valid_cors}', false);
    header("Access-Control-Allow-Methods: GET, POST, PUT");
    header("Access-Control-Allow-Headers: Content-Type");
}
     

[...]

     

请,有人可以告诉我,我在这里遇到了错误的情况,而我使用错了吗?

  • 潜在Notice: Undefined index: HTTP_ORIGIN;
  • 保证Notice: Array to string conversion + Warning: in_array() expects parameter 2 to be array, string given(即"https://Array")并且从不输入if
  • 即使您输入if,字符串'Access-Control-Allow-Origin: https://{$valid_cors}'也将被按字面理解($valid_cors 展开)因为有单引号(而不是"Access-Control-Allow-Origin: https://{$valid_cors}"有双引号);
  • HTTP标头Access-Control-Allow-Origin不接受多个值。

无论如何,我想你的意思是这样的:

$valid_cors = array('domain1', 'domain2', 'domain3');
if (isset($_SERVER['HTTP_ORIGIN']) && in_array($_SERVER['HTTP_ORIGIN'], array_map(function ($domain) { return 'https://'.$domain; }, $valid_cors), true)) {
    header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
    header('Access-Control-Allow-Methods: GET, POST, PUT');
    header('Access-Control-Allow-Headers: Content-Type');
}

(但是我不确定这将是“针对不良CORS请求的良好保护” ...)