Web

Заголовки запросов Cross-Origin (CORS) с заголовками PHP

У меня есть простой скрипт PHP, в котором я пытаюсь выполнить междоменный запрос CORS:

<?php

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

header("Access-Control-Allow-Headers: *");

...

 

Тем не менее я получаю сообщение об ошибке:

Поле заголовка запроса X-Requested-With не разрешено Access-Control-Allow-Headers

 

Что-то я делаю неправильно?

 

Ответ 1

Access-Control-Allow-Headers не допускает «приемлемого значения.

Вместо звездочки следует отправлять принятые заголовки (сначала X-Requested-With, как указано в ошибке).

Согласно MDN Web Docs 2021:

Значение «считается специальным подстановочным знаком только для запросов без учетных данных (запросы без файлов cookie HTTP или информации аутентификации HTTP). В запросах с учетными данными оно рассматривается как буквальное имя заголовка «без специальной семантики. Обратите внимание, что заголовок авторизации не может содержать подстановочные знаки и всегда должен быть указан явно.

 

 

Ответ 2

Правильная обработка запросов CORS требует больше усилий. Вот функция, которая ответит более полно (и правильно).

/**

 *  Пример CORS-совместимого метода. Он разрешает любые запросы GET, POST или OPTIONS из любого

 * места.

 *

*/

function cors() {

    if (isset($_SERVER['HTTP_ORIGIN'])) {

        header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");

        header('Access-Control-Allow-Credentials: true');

        header('Access-Control-Max-Age: 86400');    // кэш на 1 день

    }

    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))

            // можно использовать в PUT, PATCH, HEAD и т. п.

            header("Access-Control-Allow-Methods: GET, POST, OPTIONS");         

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))

            header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");

        exit(0);

    }

    echo "Это CORS!";

}

 

Замечания по безопасности

Когда браузер хочет выполнить междоменный запрос, он сначала подтверждает, что это нормально, с помощью «специального» запроса к URL. Разрешив CORS, вы сообщаете браузеру, что ответы с этого URL-адреса могут быть переданы другим доменам.

CORS не защищает ваш сервер. CORS пытается защитить ваших пользователей, сообщая браузерам, какие ограничения должны быть на обмен ответами с другими доменами. Обычно такой обмен категорически запрещен, поэтому CORS это способ проделать брешь в обычной политике безопасности браузера. Этих брешей должно быть как можно меньше, поэтому всегда сверяйте HTTP_ORIGIN с каким-то внутренним списком.

Здесь есть некоторые опасности, особенно если данные, которые обслуживает URL, обычно защищены. Вы фактически разрешаете контенту браузера, который был создан на каком-то другом сервере, читать (и, возможно, манипулировать) данные на вашем сервере.

Если вы собираетесь использовать CORS, внимательно прочтите протокол (он довольно маленький) и попытайтесь понять, что вы делаете. Для этой цели в образце кода приведен ссылочный URL.

 

Безопасность заголовка

Было замечено, что заголовок HTTP_ORIGIN небезопасен, и это так. Фактически все заголовки HTTP небезопасны для различных значений этого термина. Если заголовок не включает проверяемую подпись/hmac или весь разговор не аутентифицирован через TLS, заголовки это просто «то, что было отправлено браузеру».

В этом случае браузер сообщает: «Объект из домена X хочет получить ответ от этого URL-адреса. Это нормально?». Суть CORS состоит в том, чтобы иметь возможность ответить: «Да, я разрешаю это».

 

Ответ 3

Многие описания не упоминают, что элементов Access-Control-Allow-Origin недостаточно. Вот полный пример, который мне подходит:

<?php

    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {

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

        header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS');

        header('Access-Control-Allow-Headers: token, Content-Type');

        header('Access-Control-Max-Age: 1728000');

        header('Content-Length: 0');

        header('Content-Type: text/plain');

        die();

    }

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

    header('Content-Type: application/json');

    $ret = [

        'result' => 'OK',

    ];

    print json_encode($ret);

 

Ответ 4

Если вы хотите создать службу CORS в PHP, можно использовать этот код в качестве первого шага в вашем файле, который обрабатывает запросы:

if(isset($_SERVER["HTTP_ORIGIN"])) {

    header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");

} else {

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

}

header("Access-Control-Allow-Credentials: true");

header("Access-Control-Max-Age: 600");    // кэш на 10 минут

if($_SERVER["REQUEST_METHOD"] == "OPTIONS") {

    if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]))

        header("Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT");

    if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"]))

        header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");

    exit(0);

}

Схожие статьи

Web

Как определить, переменные PHP передаются по значению или по ссылке?

Какой выбрать CDN для сайта. Оптимизируем скорость загрузки
Web

Какой выбрать CDN для сайта. Оптимизируем скорость загрузки

Что за профессия веб-разработчик: обязанности и зарплата
Web

Что за профессия веб-разработчик: обязанности и зарплата

Web

Удаление из массива PHP по значению (не по ключу)

×