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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7564832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:45:37  来源:igfitidea点击:

how to bypass Access-Control-Allow-Origin?

javascriptphpjqueryajaxcors

提问by ETAN

I'm doing a ajax call to my own server on a platform which they set prevent these ajax calls (but I need it to fetch the data from my server to display retrieved data from my server's database). My ajax script is working , it can send the data over to my server's php script to allow it to process. However it cannot get the processed data back as it is blocked by "Access-Control-Allow-Origin"

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

I have no access to that platform's source/core. so I can't remove the script that it disallowing me to do so. (P/S I used Google Chrome's Console and found out this error)

我无法访问该平台的源代码/核心。所以我无法删除它不允许我这样做的脚本。(P/SI 使用 Google Chrome 的控制台并发现此错误)

The Ajax code as shown below:

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

      } 
  });

or is there a JSONequivalent code to the ajax script above ? I think JSONis allowed.

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

I hope someone could help me out.

我希望有人可以帮助我。

回答by Rafay

Put this on top of retrieve.php:

把它放在retrieve.php之上:

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

Note that this effectively disables CORS protection, and leaves your users exposed to attack. If you're not completely certain that you need to allow allorigins, you should lock this down to a more specific origin:

请注意,这会有效地禁用 CORS 保护,并使您的用户暴露在攻击之下。如果您不完全确定需要允许所有来源,则应将其锁定为更具体的来源:

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

Please refer to following stack answer for better understanding of Access-Control-Allow-Origin

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

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

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

回答by Rob

Okay, but you all know that the * is a wildcard and allows cross site scripting from every domain?

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

You would like to send multiple Access-Control-Allow-Originheaders for every site that's allowed to - but unfortunately its officially not supported to send multiple Access-Control-Allow-Originheaders, or to put in multiple origins.

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

You can solve this by checking the origin, and sending back that one in the header, if it is allowed:

如果允许,您可以通过检查来源并在标头中发回该来源来解决此问题:

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

Thats much safer. You might want to edit the matching and change it to a manual function with some regex, or something like that. At least this will only send back 1 header, and you will be sure its the one that the request came from. Please do note that all HTTP headers canbe spoofed, but this header is for the client's protection. Don't protect your own data with those values. If you want to know more, read up a bit on CORS and CSRF.

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

Why is it safer?

为什么更安全?

Allowing access from other locations then your own trusted site allows for session highHymaning. I'm going to go with a little example - image Facebook allows a wildcard origin - this means that you can make your own website somewhere, and make it fire AJAX calls (or open iframes) to facebook. This means you can grab the logged in info of the facebook of a visitor of your website. Even worse - you can script POSTrequests and post data on someone's facebook - just while they are browsing your website.

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

Be very cautious when using the ACAOheaders!

使用ACAO标题时要非常小心!

回答by ETAN

Warning, Chrome (and other browsers) will complain that multiple ACAO headers are set if you follow some of the other answers.

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

The error will be something like XMLHttpRequest cannot load ____. The 'Access-Control-Allow-Origin' header contains multiple values '____, ____, ____', but only one is allowed. Origin '____' is therefore not allowed access.

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

Try this:

尝试这个:

$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");
}

回答by Atif Rehman

I have fixed this problem when calling a MVC3 Controller. I added:

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

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

before my

在我之前

return Json(model, JsonRequestBehavior.AllowGet);

And also my $.ajaxwas complaining that it does not accept Content-typeheader in my ajax call, so I commented it out as I know its JSON being passed to the Action.

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

Hope that helps.

希望有帮助。

回答by mopsyd

It's a really bad idea to use *, which leaves you wide open to cross site scripting. You basically want your own domain all of the time, scoped to your current SSL settings, and optionally additional domains. You also want them all to be sent as one header. The following will always authorize your own domain in the same SSL scope as the current page, and can optionally also include any number of additional domains. It will send them all as one header, and overwrite the previous one(s) if something else already sent them to avoid any chance of the browser grumbling about multiple access control headers being sent.

使用 是一个非常糟糕的主意*,这让您对跨站点脚本持开放态度。您基本上一直想要自己的域,范围限定于您当前的 SSL 设置,以及可选的其他域。您还希望它们都作为一个标头发送。以下内容将始终在与当前页面相同的 SSL 范围内授权您自己的域,并且还可以选择包含任意数量的附加域。它会将它们全部作为一个标头发送,如果其他东西已经发送它们,则覆盖前一个(s)以避免浏览器抱怨发送多个访问控制标头的任何机会。

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.
    }
}

Usage:

用法:

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

You get the idea.

你明白了。

回答by Daniel Brockman

Have you tried actually adding the Access-Control-Allow-Origin header to the response sent from your server? Like, Access-Control-Allow-Origin: *?

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