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

197

Я делаю 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 это разрешено.

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

ETAN
источник
Во всех ответах на ваш вопрос описан способ переписать код вашего сервера, чтобы вы работали с AJAX. Ни один из них не касается обхода, как вы конкретно задали в своем вопросе. Вы нашли способ обойти этот заголовок? Я действительно сомневаюсь, что будет один.
Мораднеяд
нет способа обойти это. но вы можете поместить файл на ваш бэкэнд, который выполняет запрос. Таким образом, вы вызываете per ajax файл на вашем собственном сервере, этот файл загружает данные из retrieve.php и отправляет их обратно в ваш javascript. В этом случае нет правил CORS, блокирующих вас.
Иона Паулюс

Ответы:

367

Поместите это поверх 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

Rafay
источник
54
Это довольно небезопасно. Проверьте мой ответ внизу.
Роб
3
tnx, но вы не должны разрешать доступ ко всем источникам, как упомянуто @RobQuist в его комментарии, и в его ответе представлен лучший подход
Рафай
2
Так что я нашел эту страницу, потому что мне нужно было «обойти» контроль доступа на сервере. Решение здесь не обходит ничего, а просто правильно настраивает контроль доступа на своем собственном сервере. Если кому-то действительно нужно обойти это, они могут использовать PHP file_get_contents ($ remote_url) ;. Очевидно, есть много способов сделать это, но я так и сделал.
Шон Уиннери
1
@ShawnWhinnery это в основном акт "проксирования". Хорошее решение, если вы действительно хотите динамически загружать данные с другого сайта, который вы не можете контролировать.
Роб
1
хотел запустить скрипт PHP из ядра dotnet - перенес скрипт php на другой мой URL, но получал ошибку межсайтового скриптинга. добавил код, который вы показали, в начало PHP и работал отлично. Спасибо!
Раддевус
291

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

Вы хотите отправить несколько 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 запросов и публиковать данные на чьем-то Facebook - в то время как они просматривают ваш сайт.

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

обкрадывать
источник
12
Я думаю, вам нужно поставить http: // перед каждым элементом в списке. По крайней мере, я сделал для одного сайта, над которым я работал.
blak3r
2
К сожалению, это не похоже на работу. Я считаю, что только одно исключение может быть предоставлено для каждого вызова header ().
lewsid
5
@Shanimal & lewsid -> Я думаю, разделенная запятая не работает на самом деле. Ссылка: w3.org/TR/cors
Роб
3
Для работы со списком доменов здесь уместен ответ: stackoverflow.com/a/1850482/766177
Валентин Деспа
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
Это еще лучшее решение, которое я выложил.
Роб
7

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

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

до моего

return Json(model, JsonRequestBehavior.AllowGet);

А также я $.ajaxжаловался, что он не принимает заголовок Content-type в моем вызове ajax, поэтому я закомментировал его, поскольку знаю, что его 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();

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

mopsyd
источник
1

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

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