如何绕过访问控制允许来源?

Posted

技术标签:

【中文标题】如何绕过访问控制允许来源?【英文标题】:how to bypass Access-Control-Allow-Origin? 【发布时间】:2011-11-25 18:17:31 【问题描述】:

我正在一个平台上对我自己的服务器进行 ajax 调用,他们设置该平台阻止这些 ajax 调用(但我需要它从我的服务器获取数据以显示从我的服务器数据库中检索到的数据)。 我的 ajax 脚本正在运行,它可以将数据发送到我的服务器的 php 脚本以允许它进行处理。 但是它无法取回处理后的数据,因为它被"Access-Control-Allow-Origin"阻止了

我无法访问该平台的源代码/核心。所以我不能删除它不允许我这样做的脚本。 (P/S 我用谷歌浏览器的控制台发现了这个错误)

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);

       
  );

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

希望有人能帮帮我。

【问题讨论】:

到目前为止,您的问题的所有答案都解释了一种重写服务器代码的方法,这样您的 ajax 就可以工作了。正如您在问题中特别询问的那样,它们都不是关于绕过的。你有没有发现实际上绕过这个标题?我真的怀疑会有一个。 没有办法通过它。但是您可以在执行请求的后端放置一个文件。因此,您在自己的服务器上调用每个 ajax 文件,该文件从retrieve.php 加载数据并将它们发送回您的javascript。在这种情况下,没有 CORS 规则阻止您。 安全 websocket 协议 wss:// 不受 CORS 阻塞。 【参考方案1】:

把这个放在retrieve.php之上:

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

请注意,这会有效地禁用 CORS 保护,并使您的用户容易受到攻击。如果您不能完全确定是否需要允许所有来源,则应将其锁定到更具体的来源:

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

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

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

【讨论】:

那相当不安全。在底部查看我的答案。 tnx,但您不应该允许访问@RobQuist 在他的评论中提到的所有来源,并且在他的回答中提供了更好的方法 所以我找到了这个页面,因为我实际上需要“绕过”服务器上的访问控制。这里的解决方案不是绕过任何东西,而是简单地在他自己的服务器上正确配置访问控制。如果有人真的需要绕过这个,他们可以使用 PHP 的 file_get_contents($remote_url);。显然有很多方法可以做到这一点,但我就是这样做的。 @ShawnWhinnery 基本上是“代理”行为。如果您真的想从另一个您无法控制的网站动态加载数据,这是一个很好的解决方案。 想要从 dotnet core 运行 PHP 脚本 - 将 php 脚本移动到我的其他 URL,但出现跨站点脚本错误。将您显示的代码添加到 PHP 顶部并完美运行。谢谢!【参考方案2】:

好的,但是你们都知道 * 是一个通配符并且允许来自每个域的跨站点脚本?

您希望为每个允许的网站发送多个 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 标头时要非常小心!

【讨论】:

我认为您需要将 http:// 放在列表中每个项目的前面。至少我为我正在开发的一个网站做了。 遗憾的是,这似乎不起作用。我相信每次调用 header() 只能提供一个异常。 @Shanimal & lewsid -> 我猜逗号分隔确实不起作用。参考:w3.org/TR/cors 对于处理域列表,这里有一个相关的答案:***.com/a/1850482/766177 这样添加 4 个标头是没有意义的,因为每次调用 header() 都会替换前一个相同类型的标头。所以实际上你所做的只是设置最后一个标题。 manual entry 声明您可以设置第二个参数 false 以防止之前的标头被覆盖。【参考方案3】:

使用* 是一个非常糟糕的主意,这会让您对跨站点脚本大开方便之门。您基本上一直想要自己的域,范围仅限于您当前的 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();

你明白了。

【讨论】:

【参考方案4】:

警告,如果您遵循其他一些答案,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");

【讨论】:

这是一个比我发布的更好的解决方案。【参考方案5】:

我在调用 MVC3 控制器时解决了这个问题。 我补充说:

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

在我之前

return Json(model, JsonRequestBehavior.AllowGet);

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

希望对您有所帮助。

【讨论】:

【参考方案6】:

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

【讨论】:

这是您的服务器发送的 HTTP 标头,用于通知浏览器可以将结果显示给调用脚本,尽管脚本的源域与服务器的域不匹配。阅读Cross-Origin Resource Sharing!

以上是关于如何绕过访问控制允许来源?的主要内容,如果未能解决你的问题,请参考以下文章

如何绕过访问控制允许来源?

如何绕过访问控制允许来源?

如何绕过访问控制允许来源?

有没有办法绕过访问控制允许来源?

如何设置“访问控制允许来源:*”?

如何添加访问控制允许来源?