Как правильно очищать пользовательский ввод в PHP: защита от XSS и SQL-инъекций
Проблема в вашем подходе: смешивание контекстов
Вы совершаете классическую ошибку начинающих разработчиков — пытаетесь "очистить" данные один раз для всех случаев. На самом деле, санитизация должна зависеть от контекста использования данных. Данные для SQL-запроса, для вывода в HTML и для хранения в базе требуют разных подходов.
1. Защита от SQL-инъекций (правильная работа с БД)
Использование mysqli_real_escape_string() — это устаревший и ненадёжный метод. Современный и правильный способ — подготовленные запросы (Prepared Statements) через PDO или MySQLi. Они автоматически экранируют данные и предотвращают инъекции.
// Правильный способ с PDO
$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->execute([
':name' => $_POST['name'],
':email' => $_POST['email']
]);
// Или с MySQLi
$stmt = $connection->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param("ss", $_POST['name'], $_POST['email']);
$stmt->execute();
2. Защита от XSS (вывод в HTML)
При выводе данных на страницу используйте htmlspecialchars() с правильными параметрами. Эта функция преобразует специальные HTML-символы в их безопасные сущности.
// Правильный вывод на страницу
$safe_name = htmlspecialchars($name, ENT_QUOTES | ENT_HTML5, 'UTF-8');
echo "Привет, $safe_name!";
// Для более сложных случаев (например, если нужно разрешить некоторые теги)
// используйте библиотеку HTML Purifier
require_once 'vendor/autoload.php';
$purifier = new HTMLPurifier();
$safe_html = $purifier->purify($dirty_html);
3. Общие рекомендации по санитизации
- Фильтрация по типу данных: Используйте
filter_var()для проверки email, URL, целых чисел и т.д. - Валидация: Проверяйте, что данные соответствуют ожидаемому формату (длина, символы, диапазон).
- Никогда не доверяйте пользовательскому вводу: Всегда обрабатывайте данные как потенциально опасные.
// Пример комплексной обработки
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if ($email === false) {
die('Некорректный email');
}
$name = trim($_POST['name']);
if (strlen($name) > 100) {
die('Имя слишком длинное');
}
// Для базы данных — подготовленные запросы
// Для вывода — htmlspecialchars
4. Что не нужно делать
- Не используйте
strip_tags()— это удаляет все HTML-теги, но не защищает от XSS в атрибутах. - Не применяйте
mysqli_real_escape_string()— это не защищает от всех видов инъекций и сложно в поддержке. - Не смешивайте санитизацию с валидацией — это разные задачи.
Итог: Никогда не "очищайте" данные в одном месте для всех случаев. Используйте подготовленные запросы для БД, htmlspecialchars() для вывода в HTML и filter_var() для валидации типов данных. Для сложных случаев (редакторы WYSIWYG) применяйте HTML Purifier.
Альтернативный подход: использование современных фреймворков
Если вы разрабатываете не просто учебный проект, а реальное приложение, настоятельно рекомендую использовать один из современных PHP-фреймворков (Laravel, Symfony, Yii2). Они решают проблемы безопасности на уровне архитектуры:
- Eloquent ORM (Laravel) — автоматически использует подготовленные запросы.
- Шаблонизаторы (Blade, Twig) — по умолчанию экранируют вывод через
{{ }}, что защищает от XSS. - Встроенная валидация — правила для проверки email, URL, длины строк и т.д.
- CSRF-защита — встроенная защита от межсайтовой подделки запросов.
// Пример в Laravel
// Контроллер
public function store(Request $request) {
$validated = $request->validate([
'name' => 'required|string|max:100',
'email' => 'required|email|unique:users',
]);
User::create($validated);
// В шаблоне Blade автоматическое экранирование
// {{ $user->name }} — безопасно
// {!! $user->bio !!} — неэкранированный вывод (только для доверенного контента)
}
Фреймворки также предоставляют middleware для глобальной обработки ввода, системы логирования атак и другие инструменты безопасности. Это позволяет не думать о каждой мелочи и сосредоточиться на бизнес-логике.
Важно: Даже с фреймворком нужно понимать основы безопасности, чтобы не допустить ошибок в нестандартных ситуациях (например, при работе с файлами или API).