как обойти Access-Control-Allow-Origin?

172

Я делаю вызов ajax на свой собственный сервер на платформе, которую они устанавливают, предотвращая эти вызовы ajax (но мне нужно, чтобы они извлекали данные с моего сервера, чтобы отображать извлеченные данные из моей базы данных сервера). Мой ajax script работает, он может отправить данные на мой сервер PHP скрипт, чтобы он мог обрабатывать. Однако он не может вернуть обработанные данные, поскольку он заблокирован "Access-Control-Allow-Origin"

У меня нет доступа к этому источнику/ядру платформы. поэтому я не могу удалить script, чтобы он не разрешал мне это делать. (P/S я использовал консоль 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 script выше? Я думаю, что JSON разрешено.

Я надеюсь, что кто-то может мне помочь.

  • 0
    Во всех ответах на ваш вопрос пока объясняется, как переписать код вашего сервера, чтобы вы работали с AJAX. Ни один из них не касается обхода, как вы конкретно задали в своем вопросе. Вы нашли способ обойти этот заголовок? Я действительно сомневаюсь, что будет один.
Теги:
cors

7 ответов

335
Лучший ответ

поместите его поверх файла retrieve.php

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

Важно отметить, что header() должен быть вызван до отправки любого фактического вывода.

Неверно

<html>
<?php
header('Access-Control-Allow-Origin: *'); 
?>

Правильно

<?php
header('Access-Control-Allow-Origin: *'); 
?>
<html>
  • 51
    Это довольно небезопасно. Проверьте мой ответ внизу.
  • 3
    tnx, но вы не должны разрешать доступ ко всем источникам, как упомянуто @RobQuist в его комментарии, и в его ответе представлен лучший подход
Показать ещё 8 комментариев
265

Хорошо, но вы все знаете, что * является подстановочным знаком и позволяет выполнять межсайтовый скриптинг для каждого домена?

Вы хотели бы отправить несколько заголовков 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 допускает использование подстановочного знака - это означает, что вы можете создать свой собственный сайт где-нибудь и заставить его запускать AJAX-вызовы (или открывать iframes) на Facebook. Это означает, что вы можете получить информацию о посетителе вашего сайта в Facebook. Еще хуже - вы можете POST сценарии POST запросов и публиковать данные на ком-то Facebook - только когда они просматривают ваш сайт.

Будьте очень осторожны при использовании заголовков ACAO !

  • 11
    Я думаю, вам нужно поставить http: // перед каждым элементом в списке. По крайней мере, я сделал для одного сайта, над которым я работал.
  • 2
    К сожалению, это не похоже на работу. Я считаю, что только одно исключение может быть предоставлено для каждого вызова header ().
Показать ещё 20 комментариев
27

Предупреждение. 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");
}
  • 4
    Это еще лучшее решение, которое я выложил.
7

Я исправил эту проблему при вызове MVC3 Controller. Я добавил:

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

до моего

return Json(model, JsonRequestBehavior.AllowGet);

И также мой $.ajax жаловался, что он не принимает заголовок Content-type в моем вызове ajax, поэтому я прокомментировал его, поскольку я знаю, что его JSON передается Action.

Надеюсь, что это поможет.

5

лучше всего было бы разрешить отдельные домены, будьте осторожны с http://:

     header('Access-Control-Allow-Origin: http://www.foo.com', false);
     header('Access-Control-Allow-Origin: http://www.foo2.com', false));
  • 3
    Обязательно добавьте второй аргумент в header() и установите для него значение false , в противном случае второй заголовок заменит первый: header('Access-Control-Allow-Origin: http://www.foo.com', false);
  • 0
    хороший момент, обновил мой ответ
Показать ещё 2 комментария
3

Вы пытались добавить заголовок Access-Control-Allow-Origin в ответ, отправленный с вашего сервера? Например, Access-Control-Allow-Origin: *?

  • 1
    можешь привести пример? Спасибо
  • 1
    Это HTTP-заголовок, который ваш сервер отправляет, чтобы сообщить браузеру, что можно сообщить результат вызывающему сценарию, несмотря на тот факт, что исходный домен сценария не соответствует домену сервера. Читайте о совместном использовании ресурсов !
0

Это действительно плохая идея использовать *, что делает вас широко открытым для межсайтового скриптинга. По сути, вам все время нужен собственный домен, ограниченный вашими текущими настройками 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();

Вы поняли идею.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню