Как правильно валидировать данные из $_GET или $_REQUEST с помощью функций WordPress?
Я работаю над плагином, который требует динамического управления выводом контента. Это полностью зависит от текущей переменной $_GET
или $_REQUEST
.
В зависимости от значения переменной будет вызываться определенный метод класса для обработки запроса пользователя и вывода соответствующего контента.
Я полностью ознакомлен со страницей Валидации данных в WordPress Codex, однако не уверен, какой подход будет лучшим для моего сценария или любого другого случая санитизации переменных $_GET
или $_REQUEST
.
Как я могу санитизировать строку из переменной $_GET
или $_REQUEST
с помощью функций WordPress, если эта строка будет использоваться для вызова определенного метода класса?
Может ли этот код быть уязвимым для атак или вызвать ошибки?:
public function display_admin_page(){
if(is_admin() && isset($_GET['page'])){
global $content;
$page = sanitize_title($_GET['page']);
$method_name = 'page_'.str_replace('-', '_', $page);
if(method_exists('content', $method_name)){
// Отображаем запрошенную страницу из класса content
$thePage = $content->$method_name();
} else{
$thePage = $content->error(404);
}
echo $thePage;
}
}

WordPress не предоставляет специфических функций для валидации данных в SUPERGLOBALS.
Я использую PHP функцию filter_input, а затем экранирую её, как и любую другую ненадёжную переменную.
$url = filter_input( INPUT_GET, 'some_query_string', FILTER_VALIDATE_URL );
echo '<a href="'. esc_url( $url ). '">Нажми на меня</a>';
PHP функция filter_input принимает:

Для вашего конкретного примера:
Вы правильно санировали данные $_GET (хотя я бы использовал sanitize_key
вместо sanitize_title
— нельзя сказать, что разница существенная, но sanitize_title
предназначен для использования в URL).
Функция method_exists
вернет true для private и protected методов, поэтому если пользователь попытается вызвать private или protected метод, это приведет к ошибке без перехода на 404 страницу. (Если только метод display_admin_page
не находится в том же классе.)
Это подводит нас к главной потенциальной уязвимости: абсолютно любой может заставить выполнить любой public метод в вашем классе. По возможности всегда лучше явно указывать белый список допустимых методов. Таким образом, валидацию можно выполнить примерно так:
if ( !in_array( $_GET['page'], array( 'accepted_method', 'another_accepted_method' ) ) )
$content->error(404);

Не могли бы вы подробнее рассказать о теории потенциальной уязвимости?

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

Санізація $_GET
дуже залежить від контексту. Залежно від того, яке значення ви очікуєте і як воно має бути перевірене.
Немає універсальної відповіді на це питання. Все дуже залежить від контексту. Наприклад, ви можете написати функцію, яка видаляє всі теги та слеші з вхідних даних – це дуже безпечно, але що, якщо ви хочете зберегти тег <p>? У цьому немає нічого поганого. Сімейство функцій wp_kses() є цікавим прикладом, але це не найкраще рішення, оскільки воно враховує контекст, рівень користувача та інше. Наприклад, адміністратор може зберігати JavaScript у заголовках та вмісті записів, а користувачі з нижчим рівнем доступу – ні.
Якщо значення відоме заздалегідь, ви також можете перевірити, чи in_array( $array_valid_strings )
, щоб бути впевненим ще більше.
Тобто, існують різні ступені санізації, тому важливо тримати кінцеву мету на увазі. Я б радив звернутися до цього списку і знайти функцію або комбінацію функцій, які відповідають вашим потребам. Саме функції sanitize_ слід використовувати в цьому випадку, а не esc_. Плутанина між санізацією та екрануванням продовжується...
У моєму випадку я використовуватиму sanitize_text_field(), оскільки вона санізує рядок, отриманий від користувача або з бази даних.
- Перевіряє на наявність недійсного UTF-8,
- Перетворює одиничні символи < на сутності
- Видаляє всі теги
- Видаляє розриви рядків, табуляції та зайві пробіли
- Видаляє октети
Удачі :).
P.S. Ця відповідь цитує погляди трьох різних розробників (Джош, Міхал, Кевін).
