如何绕过Access-Control-Allow-Origin?


196

我正在对他们设置的平台上的我自己的服务器执行ajax调用,以防止这些ajax调用(但是我需要它从服务器上获取数据以显示从服务器数据库中检索到的数据)。我的ajax脚本正在运行,它可以将数据发送到服务器的php脚本以进行处理。但是由于它被"Access-Control-Allow-Origin"

我无权访问该平台的源/核心。因此我无法删除不允许这样做的脚本。(P / SI使用了Google Chrome浏览器的控制台,并发现了此错误)

Ajax代码如下所示:

 $.ajax({
     type: "GET",
     url: "http://example.com/retrieve.php",
     data: "id=" + id + "&url=" + url,
     dataType: 'json',   
     cache: false,
     success: function(data)
      {
        var friend = data[1];              
        var blog = data[2];           
        $('#user').html("<b>Friends: </b>"+friend+"<b><br> Blogs: </b>"+blog);

      } 
  });

还是JSON上面的ajax脚本具有等效的代码?我认为JSON是允许的。

我希望有人可以帮助我。


到目前为止,所有问题的答案都解释了一种重写服务器代码的方法,以便您可以使用ajax。正如您在问题中明确提出的那样,它们都与绕过无关。您是否发现实际上绕过了此标头?我真的怀疑会不会有一个。
Moradnejad

没有办法阻止它。但是您可以在执行请求的后端放置一个文件。因此,您可以每个ajax在您自己的服务器上调用该文件,该文件将从retrieve.php加载数据并将其发送回您的javascript。在这种情况下,没有CORS规则会阻止您。
乔纳·保卢斯

Answers:


365

把它放在retrieve.php之上:

header('Access-Control-Allow-Origin: *');  

请注意,这实际上会禁用CORS保护,并使您的用户容易受到攻击。如果不确定您是否需要允许所有起源,则应将其锁定为更特定的起源:

header('Access-Control-Allow-Origin: https://www.example.com')

请参考以下堆栈答案以更好地了解 Access-Control-Allow-Origin

https://stackoverflow.com/a/10636765/413670


54
那是相当不安全的。在底部查看我的答案。
罗布

3
tnx,但您不应允许访问@RobQuist在评论中提到的所有来源,并且在他的回答中提供了更好的方法
Rafay 2013年

2
因此,我找到了此页面,因为我实际上需要“绕过”服务器上的访问控制。这里的解决方案不会绕过任何东西,而只是在他自己的服务器上正确配置访问控制。万一有人真的需要绕过它,他们可以使用PHP的file_get_contents($ remote_url);。显然有很多方法可以做到这一点,但这就是我的方法。
肖恩·惠纳

1
@ShawnWhinnery基本上是“代理”行为。如果您真的想从您无法控制的另一个网站动态加载数据,则是一个很好的解决方案。
罗布

1
想从dotnet核心运行PHP脚本-将php脚本移到了我的其他URL,但出现跨站点脚本错误。将您显示的代码添加到了PHP的顶部,并且运行良好。谢谢!
raddevus

290

好的,但是你们都知道*是通配符,并且允许每个域进行跨站点脚本编写吗?

您希望Access-Control-Allow-Origin为允许的每个站点发送多个标头-不幸的是,它官方不支持发送多个Access-Control-Allow-Origin标头或放入多个来源。

您可以通过以下方法解决此问题:检查原点,然后在标头中发回该原点(如果允许):

$origin = $_SERVER['HTTP_ORIGIN'];
$allowed_domains = [
    'http://mysite1.com',
    'https://www.mysite2.com',
    'http://www.mysite2.com',
];

if (in_array($origin, $allowed_domains)) {
    header('Access-Control-Allow-Origin: ' . $origin);
}

那更安全。您可能需要编辑匹配项,然后使用一些正则表达式或类似的东西将其更改为手动功能。至少这只会发送回1标头,并且您可以确定它是请求来自的标头。请注意,所有HTTP标头都可以被欺骗,但是此标头是为了保护客户端。不要用这些值保护自己的数据。如果您想了解更多,请阅读有关CORS和CSRF的内容。

为什么更安全?

允许从其他位置访问,则您自己的受信任站点允许会话劫持。我将举一个小例子-图像Facebook允许使用通配符起源-这意味着您可以在某个地方创建自己的网站,并将其激发到Facebook的AJAX调用(或打开iframe)。这意味着您可以获取您网站访问者的Facebook登录信息。更糟糕的是,您可以POST在他人浏览您的网站时编写请求脚本并将数据发布到某人的Facebook上。

使用ACAO接头时要非常小心!


12
我认为您需要在列表中的每个项目前面加上http://。至少我在一个网站上工作过。
blak3r

2
可悲的是,这似乎不起作用。我相信每次对header()的调用只能提供一个例外。
lewsid

5
@Shanimal&lewsid->我猜逗号分隔确实不起作用。参考:w3.org/TR/cors
Rob

3
对于处理域名列表,请参见以下相关答案:stackoverflow.com/a/1850482/766177
Valentin Despa 2013年

13
这样添加4个标头是没有意义的,因为每次调用都会header()替换相同类型的前一个标头。因此,实际上您要做的就是设置最后一个标头。在手动输入状态,您可以设置第二个参数false,以防止一个头被覆盖。
BadHorsie

31

警告,如果您遵循其他一些答案,Chrome(和其他浏览器)将抱怨设置了多个ACAO标头。

错误将是这样的 XMLHttpRequest cannot load ____. The 'Access-Control-Allow-Origin' header contains multiple values '____, ____, ____', but only one is allowed. Origin '____' is therefore not allowed access.

试试这个:

$http_origin = $_SERVER['HTTP_ORIGIN'];

$allowed_domains = array(
  'http://domain1.com',
  'http://domain2.com',
);

if (in_array($http_origin, $allowed_domains))
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

6
这是我发布的一个更好的解决方案。
罗布(Rob)

7

我已经解决了在调用MVC3控制器时的问题。我补充说:

Response.AddHeader("Access-Control-Allow-Origin", "*"); 

在我之前

return Json(model, JsonRequestBehavior.AllowGet);

$.ajax还抱怨说它在我的ajax调用中不接受Content-type头,所以我将其注释掉,因为我知道它的JSON被传递给了Action。

希望能有所帮助。


2

使用*,这真的是一个坏主意,这使您可以跨站点编写脚本。您基本上一直都希望拥有自己的域,范围仅限于当前的SSL设置,还可以选择其他域。您还希望它们全部作为一个标头发送。以下内容将始终在与当前页面相同的SSL范围内授权您自己的域,并且可以选择还包括任意数量的其他域。它将全部作为一个标头发送,如果已经发送了其他标头,则覆盖先前的标头,以避免浏览器抱怨发送多个访问控制标头的任何机会。

class CorsAccessControl
{
    private $allowed = array();

    /**
     * Always adds your own domain with the current ssl settings.
     */
    public function __construct()
    {
        // Add your own domain, with respect to the current SSL settings.
        $this->allowed[] = 'http'
            . ( ( array_key_exists( 'HTTPS', $_SERVER )
                && $_SERVER['HTTPS'] 
                && strtolower( $_SERVER['HTTPS'] ) !== 'off' ) 
                    ? 's' 
                    : null )
            . '://' . $_SERVER['HTTP_HOST'];
    }

    /**
     * Optionally add additional domains. Each is only added one time.
     */
    public function add($domain)
    {
        if ( !in_array( $domain, $this->allowed )
        {
            $this->allowed[] = $domain;
        }
    /**
     * Send 'em all as one header so no browsers grumble about it.
     */
    public function send()
    {
        $domains = implode( ', ', $this->allowed );
        header( 'Access-Control-Allow-Origin: ' . $domains, true ); // We want to send them all as one shot, so replace should be true here.
    }
}

用法:

$cors = new CorsAccessControl();

// If you are only authorizing your own domain:
$cors->send();

// If you are authorizing multiple domains:
foreach ($domains as $domain)
{
    $cors->add($domain);
}
$cors->send();

你明白了。


1

您是否尝试过将Access-Control-Allow-Origin标头实际添加到服务器发送的响应中?喜欢Access-Control-Allow-Origin: *吗?


1
它是服务器发送的HTTP标头,以通知浏览器可以将结果显示给调用脚本,尽管该脚本的原始域与服务器的域不匹配。阅读跨源资源共享
Daniel Brockman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.