Intereting Posts
WP запрос исключает сообщение в течение последнего месяца / только шоу более 1 месяца AJAX с категориями фильтрации циклов $ TBA Получение перевода в $ 0 (пользовательские поля) Могу ли я использовать крючок, отличный от «init» для обработки представлений форм? Как добавить динамический фрагмент javascript в нижний колонтитул, который требует jQuery Как я могу использовать wp_get_image_editor для изменения размера изображения WordPress запрашивает данные о вашем FTP, если вы хотите запускать модули автоматического обновления / обновления Как получить имя блога при использовании WordPress Multisite Отзывчивая галерея WordPress Сброс формы сообщения администратора при сбое проверки JS разрешить редактирование настраиваемого типа сообщения, но не регулярные сообщения? WordPress использует URL-адрес, отличный от определенного в rewrite arg типа пользовательского сообщения Как отображать пользовательские изображения таксономии на index.php? esc_url возвращает неверный URL-адрес Как я могу искать все плагины для поставщика-разработчика / autoload.php?

проверьте запрашивающий URL-адрес

Использование WP 4.8.2

Каков наилучший способ проверить запрашивающий URL-адрес при обработке запроса с помощью rest-api?

Например, сайт получает запрос, и вы хотите проверить, пришел ли он с «разрешенного» URL-адреса. И сбой, если URL-адрес не разрешен.

Это не работает:

function my_check_request_url( $request, $url ) { $bits = parse_url( $url ); if ( $bits['host'] != 'example.com' ) $request = false; return $request; } add_filter( 'rest_request_from_url', 'my_check_request_url', 10, 2 ); 

Этот фильтр определенно не тот, который вы ищете. Этот фильтр срабатывает, прежде чем возвращать результат WP_REST_Request::from_url() который, как представляется, является заводским методом, который используется только внутренне для обработки вложений.

Лучший вариант – вернуть экземпляр rest_pre_dispatch фильтр rest_pre_dispatch .

Некоторые оговорки:

Как упоминалось @milo, референт не является надежным и не должен использоваться для проверки безопасности.

Кроме того, это не гарантируется.

rest_pre_dispatch приведены примеры того, как вы можете использовать фильтр rest_pre_dispatch чтобы заставить запрос терпеть неудачу, если он относится к плохому рефереру:

 function wpse281916_rest_check_referer( $result, $server, $request ) { if ( null !== $result ) { // Core starts with a null value. // If it is no longer null, another callback has claimed this request. // Up to you how to handle - for this example we will just return early. return $result; } $referer = $request->get_header( 'referer' ); if ( ! $referer ) { // Referer header is not set - If referer is required, return a WP_Error instance instead. return $result; } $host = wp_parse_url( $referer, PHP_URL_HOST ); if ( ! $host ) { // Referer is malformed - If referer is required, return a WP_Error instance instead. return $result; } if ( 'mysite.com' !== $host ) { // Referer is set to something that we don't allow. return new WP_Error( 'invalid-referer', 'Requests must contain a valid referer', compact( 'referer' ) ); } // Otherwise we are good - return original result and let WordPress handle as usual. return $result; } add_filter( 'rest_pre_dispatch', 'wpse281916_rest_check_referer', 10, 3 ); 

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

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

Допустим, у вас есть куча страниц, которые отфильтрованы как «Разрешено» . Вы можете создать отказ только для этих страниц, а затем проверить их в своем запросе.

Если nounce существует и действителен, запрос разрешен. В противном случае заблокируйте его.

@ssnepenthe 's aswer прав, говоря, что используемый вами крюк не является правильным во входящем запросе.

Запросить информацию можно сразу же на PHP, поэтому вы можете использовать самый ранний доступный крючок для проверки. И если вы хотите сделать это в контексте API запросов, вы должны использовать самый ранний крючок запроса API REST. 'rest_pre_dispatch' предложенный @ssnepenthe, в порядке, возможно, другой вариант может быть rest_authentication_errors , который позволит вам вернуть ошибку, если что-то не так.

Но Джек Йоханссон прав, говоря, что заголовки HTTP (например, заголовок реферата, используемые в aswer @ ssnepenthe) не являются надежными, так как они очень легко изменяются клиентом. Так было бы, как поставить охранника перед дверью, который просто спрашивает: «Безопасно ли вам войти?» всем, кто хочет пойти: это не сработает.

Но решение, предложенное Джеком Йоханссоном (nonce), не является реальным решением: вся точка nonces должна меняться со временем, а публичная конечная точка API не может иметь вещей, которые изменяются в зависимости от времени. Кроме того, WP nonces являются доверчивыми только тогда, когда есть зарегистрированный пользователь, что может быть не так для общедоступного API, и если пользователь вошел в систему, вероятно, нет причин проверять входящий домен: вы доверяете пользователю, а не пользователь машина.

Так что делать?

Ну, даже если HTTP-заголовки не являются надежными, не вся информация, доступная в $_SERVER поступает из заголовков.

Обычно все значения $_SERVER чьи ключи запускаются с HTTP_ поступают из заголовков и должны рассматриваться как небезопасные пользовательские ввод .

Но, например, $_SERVER['REMOTE_ADDR'] содержит IP-адрес, используемый для подключения TCP к вашему серверу, что означает, что он является надежным 1 .

Что также означает, что либо:

  • правильно настроив сервер для генерации значения $_SERVER['REMOTE_HOST'] (например, в Apache вам понадобятся HostnameLookups On Внутри вашего httpd.conf ) это значение
  • используя gethostbyaddr чтобы выполнить обратный поиск DNS для разрешения имени домена IP, хранящегося в $_SERVER['REMOTE_ADDR']

вы могли бы получить достаточно надежно имя хоста, которое вы могли бы использовать для проверки со списком белых (для кода вы могли бы адаптировать код из asper @ ssnepenthe, где вы заменили $referer = $request->get_header('referer') на $referer = gethostbyaddr($_SERVER['REMOTE_ADDR']) ).

Но есть проблема .

Если ваш веб-сервер находится за обратным прокси-сервером (на самом деле это довольно распространенное решение), TCP-соединение с веб-сервером фактически производится прокси-сервером, поэтому $_SERVER['REMOTE_ADDR'] будет IP-адресом прокси-сервера, а не IP-адресом клиент, который первоначально отправил запрос.

Исходный IP-адрес запроса в таких случаях обычно доступен как $_SERVER['HTTP_X_FORWARDED_FOR'] , но, будучи одним из тех значений $_SERVER которые начинаются с HTTP_ он не заслуживает доверия.

Таким образом, если ваш веб-сервер находится за обратным прокси-сервером 2, даже $_SERVER['REMOTE_ADDR'] не будет полезен для такого охранника, и белый список на основе домена может быть реализован только на уровне прокси-сервера.

Короче говоря, надежное решение для защиты конечных точек API должно быть реализовано с использованием какого-то реального механизма аутентификации (например, oAuth) или должно выполняться непосредственно в конфигурации сервера, а не на уровне приложения.


Заметки

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

2 Если вы не знаете, находитесь ли вы за обратным прокси, вы можете отправить запрос с вашего локального ПК и проверить, соответствует ли $_SERVER['REMOTE_ADDR'] на сервере локальному IP $_SERVER['HTTP_X_FORWARDED_FOR'] ПК, а также если $_SERVER['HTTP_X_FORWARDED_FOR'] и он соответствует локальному IP-адресу ПК.