Использование 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 );
$request
и$url
как выглядят переменные с помощьюvar_dump
или аналогично, я обнаружил, что проверка входов и выходов всегда приводит к правильному ответу.Ответы:
Этот фильтр определенно не тот, который вы ищете. Этот фильтр срабатывает перед возвратом, результатом
WP_REST_Request::from_url()
которого является фабричный метод, который используется только для внутренних операций.Лучший вариант - вернуть
WP_Error
экземпляр вrest_pre_dispatch
фильтр .Некоторые предостережения:
Как упомянул @milo, реферер ненадежен и не должен использоваться для проверки безопасности.
Кроме того, это не гарантируется быть установленным.
Вне зависимости от этого, вот пример того, как вы можете использовать
rest_pre_dispatch
фильтр для сбоя запроса, если он поступил от плохого реферера:источник
Все, что вы получаете от клиента, считается вводом пользователя и не должно быть доверенным. Поскольку заголовком можно легко манипулировать и злоупотреблять, я предлагаю не использовать этот метод, если вы полагаетесь на него для получения конфиденциальных данных.
Если запросы поступают со страницы, у вас может быть другой подход. В противном случае любой может отправить запрос в API из ниоткуда и сменить реферера.
Допустим, у вас есть несколько страниц, которые отфильтрованы как «Разрешенные» . Вы можете создать существительное только для этих страниц, а затем подтвердить их в своем запросе.
Если существительное существует и является действительным, запрос разрешается. В противном случае заблокируйте это.
источник
Ответ @ssnepenthe прав, говоря, что используемый вами хук не является правильным во входящем запросе.
Информация запроса немедленно доступна для PHP, поэтому вы можете использовать самый ранний доступный хук для их проверки. И если вы хотите сделать это в контексте API запроса, вы должны использовать самый ранний хук запроса REST API.
'rest_pre_dispatch'
предложено @ssnepenthe хорошо, может быть, другой вариант может бытьrest_authentication_errors
, который позволит вам вернуть ошибку в случае, если что-то не так.Но Джек Йоханссон прав, говоря что HTTP-заголовки (например, заголовок referer, используемый в aswer @ ssnepenthe) не являются надежными, так как они очень легко изменяются клиентом. Так что это все равно, что поставить охранника перед дверью, который просто спросит: "Безопасно ли вам входить?" всем, кто хочет войти: это не сработает.
Но решение, предложенное ответом Джека Йоханссона (одноразовый номер), также не является реальным решением: весь смысл одноразовых номеров состоит в том, чтобы изменяться со временем, и у конечной точки общедоступного API не может быть вещей, которые изменяются в зависимости от времени. Более того, одноразовые номера WP заслуживают доверия только тогда, когда есть вошедший в систему пользователь, что может не соответствовать общедоступному 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']
вы можете получить достаточно надежно имя хоста , которое вы могли бы использовать , чтобы проверить против белого списка (для кода, вы можете адаптировать код из @ ssnepenthe - х aswer , где вы бы заменить
$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']
он присутствует, и соответствует ли он IP-адресу локального ПК.источник