Философия валидации данных
Основной принцип — не доверять никаким данным и всегда проверять или очищать данные, получаемые из любых источников: POST/GET/AJAX параметры, БД, внешние API, RSS-каналы. Остальные принципы, вытекающие из этого, рассмотрим ниже.
Если игнорировать валидацию данных, сайт взломают — это лишь вопрос времени!
Проверка (валидация) данных
Валидация данных — это проверка входящих данных и определение, можно ли их использовать.
Данные формы
Входящие данные обычно поступают из формы, но это могут быть и внешние источники: RSS-каналы, AJAX-запросы, другие API.
Примеры валидации данных:
- Проверить, что обязательные поля заполнены.
- Проверить, что номер телефона содержит только цифры и знаки препинания.
- Проверить, что почтовый адрес корректен.
- Проверить, что введённое количество больше 0.
Валидация должна выполняться как можно раньше — сразу после получения данных. Только потом с ними можно работать.
Можно проверять форму с помощью JavaScript до отправки. Но полагаться на это нельзя: JavaScript — это клиентская часть, которую легко отключить. Окончательную проверку данных всегда нужно делать на PHP!
Очистка данных
Если данные нужно принять или вывести на экран, их надо очистить от опасных символов. Очистка нужна:
- перед сохранением в БД
- перед выводом на экран
- иногда перед проверкой — например, удалить пробелы в начале и конце строки и только потом проверять.
Чем проверять входящие данные?
Для этого есть множество функций из ядра WordPress и PHP. Полный список.
Принципы проверки и очистки данных
Не доверяйте никаким данным
Любые данные от пользователя потенциально опасны, даже если они выводятся только в админке.
Даже данные из базы нужно считать потенциально опасными, так как они могут использоваться в разных контекстах. Например, заголовки могут содержать кавычки и вызвать ошибку в HTML-атрибуте.
Проверяйте на входе, очищайте на выходе
Данные нужно очищать перед выводом — как можно позже, в идеале прямо перед выводом.
Принимаемые данные нужно проверять и очищать как можно раньше. Но при этом — ещё раз перед записью в базу, ведь очистка для SQL и начальная очистка — это разные вещи.
Доверяйте WordPress
Многие функции WordPress уже проверяют и очищают данные. Если вы используете такие функции, не нужно отдельно заботиться об этом. Например:
$posts = get_posts( array( 's' => $_GET['s'] ) );
Примеры: $wpdb->update(), $wpdb->insert(), wp_update_post(), the_title(), the_content() и т.д.
Лучше лишний раз очистить
Не всегда нужна очистка, но лучше очистить лишний раз, чем потом отлавливать баги или уязвимости.
Белый список
Разрешать только те данные, которые явно допустимы.
Пример с оператором сравнения
$val = '1 непроверенная строка'; if ( 1 === $val ) { echo 'Допустимое значение'; } else { wp_die( 'Недопустимое значение' ); }
Важно использовать ===, а не ==. Иначе строка '1' станет числом.
Пример с in_array()
$val = '1 опасная строка'; $safe_values = [ 1, 5, 7 ]; // белый список if ( in_array( $val, $safe_values, true ) ) { // `true` указывает что нужно учитывать тип данных - точная проверка echo 'Допустимое значение'; } else { wp_die( 'Недопустимое значение' ); }
Обязательно используйте true как третий аргумент, иначе тип будет проигнорирован.
Пример со switch()
$val = '1 опасная строка'; switch ( true ) { case 1 === $val: // нужно отдельно проверять с учетом типа, а не надеется на switch echo 'Допустимое значение'; break; default: wp_die( 'Недопустимое значение' ); }
Используйте === для точной проверки, иначе тип преобразуется автоматически.
Чёрный список
Запрещать конкретные значения. Работает похоже на белый список, но наоборот — блокирует опасные значения.
Данные из числовой колонки в БД всегда безопасны
Если данные в колонке — число, то при записи туда ничего другого не попадёт.
Приводите такие данные к числу на входе:
$count = (int) $_GET['count']; // 10 $price = (float) $_POST['price']; // 52.5
Примеры
Пример проверки данных
Нужно убедиться, что данные пришли в нужном формате, в противном случае их не допускать.
// Пройдет если $data состоит только из букв и цифр: 'AbCd1zyZ9' - да, 'foo!#$bar' - нет if ( ! ctype_alnum( $data ) ) { wp_die( 'Неверный формат' ); } // проверка по символам: могут быть только 0-9.- if ( preg_match( '/[^0-9.-]/', $data ) ) { wp_die( 'Неверный формат' ); }
Пример очистки данных
Когда независимо от обстоятельств нужно принять данные, то их можно очистить от опасных символов.
// когда нужно получит только число $trusted_integer = (int) $untrusted_integer; // когда нужно получит только строчные буквы $trusted_alpha = preg_replace( '/[^a-z]/i', "", $untrusted_alpha ); // когда нужно получит стандартный ярлык (slug) $trusted_slug = sanitize_title( $untrusted_slug );