Безопасно ли исправлять ошибки Access-Control-Allow-Origin (CORS origin) с помощью директивы заголовка php?
Я пытаюсь отобразить форму Formidable Pro Form с одного сайта WordPress на другом. Я следовал документации API разработчика и REST API, но столкнулся с проблемой CORS.
Затем я нашел предложение в теме форума добавить эту строку кода в functions.php
сайта, где находится оригинальная форма:
header("Access-Control-Allow-Origin: *");
Я попробовал этот код, и он отлично сработал.
Мой вопрос: создает ли этот код риски безопасности или другие уязвимости?
Решение кажется слишком простым для проблемы, с которой сталкиваются многие люди.
Буду признателен за ваш отзыв.
Да, вы открываете свой сайт для AJAX-запросов из любого скрипта в интернете.
Лучше ограничить источник одним конкретным удаленным доменом, с которого вы потребляете API, как в этом примере:
header("Access-Control-Allow-Origin: http://mozilla.com");
Однако, как указано в документации Mozilla, клиент может подменить источник, тем не менее ограничение сайтов, с которых обычный пользователь может подключиться, служит сдерживающим фактором для некоторых атак.
Еще лучше, вы можете ограничить запросы только теми методами, которые действительно нужно разрешить, суть в этом сниппете, который работает для нескольких доменов, если переменная $_SERVER['HTTP_ORIGIN']
заполнена:
add_action('rest_api_init', function() {
/* отключаем стандартную функцию */
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
/* затем добавляем свой фильтр */
add_filter('rest_pre_serve_request', function( $value ) {
$origin = get_http_origin();
$my_sites = array( 'http://site1.org/', 'http://site2.net', );
if ( in_array( $origin, $my_sites ) ) {
header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) );
} else {
header( 'Access-Control-Allow-Origin: ' . esc_url_raw( site_url() ) );
}
header( 'Access-Control-Allow-Methods: GET' );
return $value;
});
}, 15);
Как видите, этот сниппет использует функцию get_http_origin, предоставляемую WordPress, но она вернет null или пустое значение, если ключ HTTP_ORIGIN
не заполнен в массиве $_SERVER
, следовательно, он недоступен для PHP-скрипта, возможно, потому что он заблокирован используемым прокси cloudflare. Я бы быстро проверил с помощью скрипта с <?php phpinfo(); ?>
, заполнена ли эта переменная.
Возможно, исходный сайт указан в другом заголовке cloudflare, и вы можете использовать его в функции, подключенной к фильтру http_origin
. Если вы запутались на этом этапе, отредактируйте исходный вопрос, опубликовав содержимое переменной _SERVER, за исключением путей файловой системы или паролей.
Буду рад помочь.

Спасибо. Первое решение сработало для меня. Но так как у меня 4 сайта, которым я хочу разрешить доступ к основному сайту, мне нужно повторить эту строку 4 раза, меняя URL сайта, или можно объединить это в одну команду? Спасибо.

Конечно можно, я обычно разрешаю доступ к API только для нескольких сайтов. Я обновил свой ответ с проверкой для этого случая. Если это сработает, не могли бы вы проголосовать за ответ?

Первое решение работало только для одного домена. Если я повторял строку, это не работало. Я попробовал метод из этой ветки ссылка, но он тоже не сработал.
Когда я применил второе решение, вот что я получил: XMLHttpRequest cannot load https://coptic-treasures.com/wp-json/frm/v2/forms/6?return=html. The 'Access-Control-Allow-Origin' header has a value 'https://coptic-treasures.com' that is not equal to the supplied origin. Origin 'https://audio.coptic-treasures.com' is therefore not allowed access.

Нельзя использовать заголовок Allow Origin более одного раза. Я обновил свой ответ с дополнительными инструкциями, чтобы помочь вам в отладке проблемы, потому что постоянное возвращение одного и того же сайта не должно происходить - система должна распознавать список ваших доменов, который вы передаёте в массив. Пожалуйста, обновите ваш вопрос, добавив данные переменной $_SERVER, возвращаемые функцией phpinfo()
, исключая пароли и пути файловой системы. Буду рад помочь.

У меня ушло около 2 дней, чтобы разобраться, как убрать доступ CORS из WP-JSON API. Спасибо за это. Удалите вызов функции rest_send_cors_headers
!

Предыстория - браузеры ограничивают удаленный доступ скриптов только сайтом, с которого они были загружены. Если бы такая проверка не выполнялась, при посещении сайта X было бы возможно отправлять данные в ваш аккаунт Gmail (если вы авторизованы) без необходимости угадывать логин и пароль, потому что браузер автоматически отправлял бы соответствующие аутентификационные куки в Gmail.
Протокол CORS существует, чтобы помочь ослабить это ограничение, когда это необходимо.
Поэтому вопрос, который вы должны задать себе - нужен ли он мне? С одной стороны, трудно представить, зачем он может понадобиться 99% сайтов на WordPress, с другой - куки WordPress относительно недолговечны, и 99% сайтов на WordPress вряд ли станут целью подобных случайных атак.
Я бы сказал, что поскольку REST API в WordPress позволяет вносить изменения и имеет доступ к приватной информации, вам не следует использовать REST API в вашем решении, если вам нужно включить CORS. Лучше написать собственный API только для чтения данных.

OP говорит не о 99% сайтов на WP, а о своих собственных, и согласно вопросу, необходимо сделать доступными ресурсы с другого сайта.

В том, что суть в том, чтобы ответить на вопрос, это цель данного сайта.

@JesúsFranco, думаю, моя репутация показывает, что я знаю, как отвечать на вопросы, и мне не нужны ваши советы?

Итак, у вас есть конкретное представление о том, как автор вопроса может решить эту проблему?

@JesúsFranco, автор вопроса спрашивал, безопасно ли это. Ответ — нет. Очевидное решение — не делать вещи, которые требуют использования CORS

Мой вопрос основан на вашем утверждении о риске доступа к приватной информации. На самом деле, одним из ключевых принципов API является то, что только разработчик может предоставить доступ к приватной информации, так как сам API в исходном виде этого не делает.

@JesúsFranco Насколько мне известно, API использует куки для аутентификации, и пользователи с ролью администратора, например, могут получить практически любую информацию. Если полностью отключить CORS и с помощью фишинга заманить вас на мой сайт, я могу написать JS-код, который выполнит любые операции на вашем сайте, потому что вы уже аутентифицированы в нём, и ваш браузер просто отправит куки аутентификации в составе запроса. Мне даже не придётся угадывать ваше имя пользователя... Блокировки доступа к "write" эндпоинтам недостаточно, так как администратор может получить конфиденциальную информацию.

Возможно, сейчас через API нельзя получить много информации, но его цель — полностью заменить админку, поэтому он должен будет предоставлять клиенту все существующие данные.

Спасибо, Марк, понимание механизма, который можно использовать для превращения доступа к API в небезопасный, очень полезно для оценки рисков и принятия решения о том, можно ли использовать патч, ограничив использование методов, доступных для удаленных скриптов, или же нужно разрабатывать совершенно новый API.

@MarkKaplun Я новичок в WP-API, поэтому у меня вопрос. Разрешение CORS только для методов 'GET' также может сделать сервер уязвимым?

@shariqkhan, вероятно, лучше задать этот вопрос на SO или Security Stack, но в целом ответ — да. CORS следует отключать только для доверенных сайтов или поддоменов, которые не выполняют никаких действий без отправки учетных данных для авторизации в теле запроса. Пока REST API использует cookies для аутентификации и работает на том же домене, что и сайт WordPress, следует быть очень осторожным с его отключением.

но опять же, если вы отключите CORS только для одного конкретного URL, который, как вы знаете, не может быть использован для причинения вреда, то это может быть допустимо. Дело не столько в GET vs POST, сколько в том, что фактически происходит на этом конечном пункте

Спасибо @MarkKaplun, я видел множество ваших ответов на SO/SE, так что знаю, что вы говорите с пониманием дела. Вероятно, я задам этот вопрос на SO, хотя чувствую, что его могут закрыть как "слишком широкий" или как "дубликат". Мне интересно, как различные сайты, такие как Github, Twitter (и многие сайты на WordPress тоже), открывают свои API, отключая CORS-ограничения для всех. У меня было впечатление, что если отключать CORS только для GET-запросов, это достаточно безвредно, так как вы лишь разрешаете другим получать данные, а не изменять что-либо?

Разница между WordPress и другими сайтами в том, что они не используют аутентификацию через куки для API, а использование API требует явной отправки данных пользователя и пароля в каждом запросе. API WordPress <предупреждение: ворчание> был плохо спроектирован в этом отношении, и, вероятно, не мог быть спроектирован лучше, так как ему приходилось поддерживать небезопасную передачу данных по HTTP, что не позволяло использовать метод с пользователем/паролем, поскольку любой, кто слушает (например) WiFi, мог бы перехватить эти данные.

То, что у вас установлены куки при входе в систему, это то, что атакующие могут использовать для отправки AJAX-запросов, как если бы они исходили от вас. При включённом CORS такие запросы будут отклоняться для других доменов, и поскольку только вы контролируете свой домен, вы в безопасности. Чем больше сайтов, для которых вы отключаете CORS, тем больше мест, где злоумышленник может получить контроль и атаковать вас, заманивая вас на эти сайты. Вопрос был о полном отключении CORS для всех сайтов, что очень плохо, но если вы отключаете его для других доменов, которые полностью под вашим контролем, хотя и не является хорошей практикой, не так опасно.
