як обійти 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 працював. Жоден із них не стосується обходу, як ви конкретно задали у своєму запитанні. Чи знайшли ви все-таки фактично обійти цей заголовок? Я дуже сумніваюся, що був би такий.
Мораднеджад

немає способу його обійти. але ви можете помістити файл у свій бекенд, який виконує запит. Отже, ви закликаєте per ajax файл на своєму власному сервері, який завантажує дані з retrieve.php і відправляє їх назад у ваш javascript. У такому випадку немає правил CORS, що блокують вас.
Йона Паулюс

Відповіді:


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 у своєму коментарі, і у своїй відповіді запропонував кращий підхід
Рафай

2
Тому я знайшов цю сторінку, бо мені потрібно було фактично "обійти" Контроль доступу на сервері. Тут рішення не обходить нічого, а просто правильно налаштувати контроль доступу на власному сервері. У випадку, якщо комусь там насправді потрібно обійти це, вони можуть використовувати файл PHP-файлу_get_contents ($ remote_url) ;. Очевидно є багато способів зробити це, але ось як я це зробив.
Shawn Whinnery

1
@ShawnWhinnery, що в основному є актом "наближення". Гарне рішення, якщо ви дійсно хочете динамічно завантажувати дані з іншого веб-сайту, за яким ви не маєте контролю.
Роб

1
хотів запустити скрипт PHP з ядра dotnet - переміщений 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 дозволяє мати посилання на підстановку - це означає, що ви можете зробити свій власний веб-сайт десь і зробити його закликом AJAX (або відкрити iframe) у facebook. Це означає, що ви можете захопити інформацію про вхід у facebook відвідувача вашого веб-сайту. Ще гірше - ви можете скриптувати POSTзапити та розміщувати дані у чиємусь фейсбуці - лише під час перегляду вашого веб-сайту.

Будьте дуже обережні, використовуючи 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скаржився, що він не приймає заголовка типу вмісту в моєму виклику ajax, тому я прокоментував це, оскільки знаю, що його JSON передається в дію.

Сподіваюся, що це допомагає.


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, який ваш сервер надсилає, щоб повідомити веб-переглядачу, що добре розкрити результат виклику скрипту, незважаючи на те, що початковий домен сценарію не відповідає домену сервера. Читайте про перехресне походження ресурсів !
Даніель Брокман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.