- Заголовки запросов Cross-Origin (CORS) с заголовками PHP
- Ответ 1
- Ответ 2
- Замечания по безопасности
- Безопасность заголовка
- Ответ 3
- Ответ 4
- fastcodenote
- Подключение шрифтов с другого домена
- PHP
- Enabling Cross-Origin Resource Sharing CORS for PHP
- Setting required headers using PHP
- PHP code to enable CORS
- 5 thoughts on “ Enabling Cross-Origin Resource Sharing CORS for PHP ”
Заголовки запросов Cross-Origin (CORS) с заголовками PHP
У меня есть простой скрипт PHP, в котором я пытаюсь выполнить междоменный запрос CORS:
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: «);
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: «);
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 недостаточно. Вот полный пример, который мне подходит:
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: «);
> 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: «);
exit(0);
>
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
fastcodenote
В наши дни не знать что такое CORS (wiki), сродни прогулки тёмной ночью по последнему этажу, недостроенной высотки где-нибудь за городом, в неблагополучном районе. Т.е. смертеподнобно, а особенно если вы фронт-енд разработчик.
Более подробно вы можете ознакомиться перейдя по ссылкам в конце текста, я же скажу вкратце, CORS это набор HTTP заголовков, которые позволяют объяснить браузеру и серверу, что они хоть и из разных доменов, но одной крови работать могут вместе. Т.е. кросс-доменные зпросы поддерживаються. Кто не знает, то запрос из браузера посредством старого, доброго JavaSctipt недавно, так на чистоту, без костылей сделать было невозможно. Ура, эти мрачные времена канули в лету. Пришёл на момощь CORS.
Речь пойдет именно о процессе использования и базовой настройки заголовков сервера, и отсыла запросов клиента с использованием jQuery.
Сервер, который мнит себя крутым сервисом, настолько куртым что хочет предоставить поддержку кросс-доменных запросов. Должен клинету сообщить об этом. Отправив следующие заголовки:
- Access-Control-Allow-Origin
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
Это тот минимум, который необходим для успешной работы наших кросс-доменных запросов. немного рапишем что, к чему:
Access-Control-Allow-Origin — (обязательный) собственно список разделенный пробелами допустимых доменнов (источников), которые будут ломиться делать запросы к нам на сервер. Из особенностей: регистрозависим, поддерживает маски, например, http://api.superservice.com/, http://*.superservice.com/ или, как вы могли догадаться просто «звездочка» *. Этот заголовок будет сравниваться с заголовком Origin клиентского запроса.
Access-Control-Allow-Method — (обязательный) это список доступных HTTP методов, разделенных запятыми. Особое внимание стоит уделить тому, что «звездочка» аля * работать не будет!
Access-Control-Allow-Headers — (обязательный вместе с Access-Control-Request-Headers) список через запятую заголовков разрешенных в запросе.
Пример настройки для Apache:
# CORS заголовки (добавте это, например, в .htaccess) Header always set Access-Control-Allow-Origin: "*" Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS" Header always set Access-Control-Allow-Headers "X-Requested-With, content-type"
Давайте разберемся, что тут происходит? А происходит следующее, запросы будут обработанны с любого источника, если они будут одного из перечисленных в Header always set Access-Control-Allow-Methods типов, так же будут подерживаться заголовки X-Requested-With и content-type
Теперь, предположим, что сервис у нас крутится по адресу http://api.superservice.com/ , а GET запрос нам надо сделать со странички http://pure.client.net/. Это не сложно сделать, к примеру с jQuery:
jQuery.ajax(< url: 'http://api.superservice.com/credit-card-ids', type: 'GET', contentType: 'application/json', // тот тип контента, который вы будете получать от своего сервиса headers: < >, // Разные заголовки, нестандартные заголовки, не забудте их указать в Access-Control-Allow-Headers success: function (res) < console.log(res); >, error: function () < . >>);
Думаю самое время упомянуть о неприятном моменте с AngularJs если вам понадобиться сделать кросс-доменый запрос с помощью $http или $resource, то надо будет удалить один заголовок, делается это так:
myApp.config(['$httpProvider', function($httpProvider) < $httpProvider.defaults.useXDomain = true; delete $httpProvider.defaults.headers.common['X-Requested-With']; >]);
Такое поведение странно, для меня, по крайней мере, несмотря на то что заголовок X-Requested-With вы укажите Access-Control-Allow-Headers не исключены проблемы с запросами. Ходят слухи что это бага AngularJs, кому интересно, если найдете что, отпишитесь в коментах.
Переходим к интересным запросам типа POST/PUT/DELETE, всех их объединяет то что они пытаются что-то изменить на сервере. Но как сделать такой запрос кросс-доменным? Сначала надо получить список заголовков типа Access-Control-*, делается это предварительным OPTIONS запросом. Который может вернуть тот же набор Access-Control-*, что и обычный метод GET.
На сервере если вы больше нигде и не для чего более не будете использовать OPTIONS запросы, то можете смело на все запросы типа OPTIONS отвечать необходимыми заголовками в том числе и такими заветными для нас как CORS заголовки. Если кто не понял то имееться ввиду добавить правило для всех запросов типа OPTIONS в роутах вашего любимого фреймворка. Или же сделать обработку руками.
Этот предварительный запрос (prefligth-запрос), делается автоматически jQuery или тем же Angular, по-тому же URL что и ваш основной запрос POST/PUT/DELETE поэтому будте внимательны если вы не сделаете правильной обработку запросов типа OPTIONS то и запрос POST/PUT/DELETE у вас сделать не получиться, из-за политики безопасности, который следуют браузеры.
Пример запроса POST с использованием jQuery.
jQuery.ajax(< ulr: 'http://api.superservice.com/credit-card-ids', type: 'POST', data: '', // внимание! если вы передатите параметр как объект то это будет Query String, в данном случае это Request Body, т.к. тут передана строка. contentType: 'application/json', // тот тип контента, который вы будете получать от своего сервиса headers: < >, // Разные заголовки, нестандартные заголовки, не забудте их указать в Access-Control-Allow-Headers success: function (res) < console.log(res); >, error: function () < . >>);
Я старался изложить кратко, в справочном виде, не очень получилось :), но думаю многим кто прочитал это сэкономит время. Ниже список источников, который позволят вам более глумого изучить вопрос CORS
Подключение шрифтов с другого домена
Как и кроссдоменные запросы AJAX, подключение шрифтов с другого домена или поддомена по умолчанию запрещены и вызывают ошибку: Access to font at . from origin . has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Чтобы разрешить доступ к шрифтам на ресурсе донора, нужно убедится что у Apache включён модуль mod_headers, посмотреть можно в phpinfo() :
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Origin "https://example.com"
Также существуют параметры: Access-Control-Allow-Methods – определяет разрешенные методы при обращении к ресурсу.
Header set Access-Control-Allow-Methods: "POST, GET, OPTIONS"
Header set Access-Control-Allow-Headers: "X-PINGOTHER, Content-Type"
PHP
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: X-Requested-With, content-type');
Enabling Cross-Origin Resource Sharing CORS for PHP
This post is an addition to Enabling Cross-Origin Resource Sharing CORS for Apache to show you how to enable Cross-Origin Resource Sharing CORS for PHP. Thus, in case you don’t have access to the .htaccess you can simply enable CORS for PHP using the following steps.
Setting required headers using PHP
As explained in Enabling Cross-Origin Resource Sharing CORS for Apache you need to make sure that responses to cross-domain requests to your server (e.g. through Ajax requests using jQuery) need to include a set of required headers to be accepted by the client browser. These are
- Access-Control-Allow-Origin
- Access-Control-Allow-Methods
- Access-Control-Max-Age
- Access-Control-Allow-Headers
Make sure that Access-Control-Allow-Origin is set a domain value actually allowed by your server. In theory you could use ‘*‘ as well, but some browsers (e.g. Firefox) will simply ignore it and CORS will not work.
PHP code to enable CORS
The following snippet should give you a quick overview about the required HTTP headers to set for CORS to work.
First, it defines a list of allowed origin domains based on regular expressions. This list will be checked against $_SERVER[‘HTTP_ORIGIN’], i.e. the Origin header specified in the client request. If one origin entry from the list matches the required CORS headers will be set. This setup also takes care of the CORS pre-flight request.
// array holding allowed Origin domains $allowedOrigins = array( '(http(s)://)?(www\.)?my\-domain\.com' ); if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN'] != '') < foreach ($allowedOrigins as $allowedOrigin) < if (preg_match('#' . $allowedOrigin . '#', $_SERVER['HTTP_ORIGIN'])) < header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS'); header('Access-Control-Max-Age: 1000'); header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With'); break; >> >