Представьте, что вы построили дом. Красивый, уютный, с новенькой мебелью. Но забыли закрыть окна и двери. Рано или поздно кто-то зайдет и унесет самое ценное. Так и с PHP-приложением. Можно написать крутой функционал, но если не думать о безопасности, данные пользователей могут уплыть к злоумышленникам. Эта статья — про то, как закрыть те самые «окна» и «двери» в вашем коде. Без паники, только практика.

1. SQL-инъекции: как злоумышленники крадут базу данных

SQL-инъекция — это когда хакер вставляет в запрос свой SQL-код через поля ввода. Например, в форме логина вместо имени пользователя он вводит что-то вроде admin' OR '1'='1. Если вы просто вставляете переменные в запрос, база данных может выполнить этот код и отдать все данные.

Как защититься? Используйте подготовленные запросы (prepared statements). Они отделяют данные от кода. Вот пример на PHP с PDO:

$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $_POST['email']]);
$user = $stmt->fetch();

Видите? Вместо того чтобы вставлять $_POST['email'] прямо в строку, мы используем плейсхолдер :email. PDO сам экранирует данные. Это просто и надежно.

Правило: Никогда не вставляйте пользовательские данные напрямую в SQL-запрос. Всегда используйте подготовленные запросы или ORM (например, Eloquent в Laravel).

2. XSS-атаки: когда скрипты выполняются на вашем сайте

XSS (Cross-Site Scripting) — это когда злоумышленник внедряет JavaScript-код в страницу. Например, через комментарий или поле ввода. Этот код может украсть куки, перенаправить пользователя на фишинговый сайт или изменить содержимое страницы.

Основная защита — экранирование вывода. В PHP есть функция htmlspecialchars(). Она превращает специальные символы в безопасные HTML-сущности. Пример:

$comment = $_POST['comment'];
echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');

Если пользователь введет <script>alert('XSS')</script>, на экране появится просто текст, а не выполнится скрипт. Для контекста JavaScript (например, в атрибутах) используйте дополнительные проверки.

Тип XSSОписаниеЗащита
Отраженный (Reflected)Код передается через URL или форму и сразу отображаетсяЭкранирование вывода, валидация ввода
Хранимый (Stored)Код сохраняется в базе данных (например, в комментариях)Экранирование при выводе, Content Security Policy
DOM-basedКод выполняется через изменение DOM на клиентеИзбегать опасных JS-методов (innerHTML)

3. CSRF: как защититься от поддельных запросов

CSRF (Cross-Site Request Forgery) — это когда злоумышленник заставляет пользователя выполнить нежелательное действие на сайте, где тот авторизован. Например, перевести деньги или сменить пароль. Атака работает, потому что браузер автоматически отправляет куки.

Решение — CSRF-токены. Это уникальные значения, которые генерируются на сервере и вставляются в формы. При отправке запроса сервер проверяет токен. Пример на PHP:

session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
?>

На сервере проверяем:

if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die('CSRF-атака обнаружена');
}

Токен должен быть уникальным для каждой сессии или формы. Не храните его в куках.

Лайфхак: Используйте фреймворки (Laravel, Symfony). Они уже имеют встроенную защиту от CSRF. Не изобретайте велосипед.

4. Управление сессиями и безопасность паролей

Сессии хранят данные пользователя на сервере. Если злоумышленник украдет ID сессии, он сможет войти под чужим аккаунтом. Поэтому:

  • Используйте HTTPS, чтобы трафик был зашифрован.
  • Устанавливайте флаг HttpOnly для кук сессии (чтобы JavaScript не мог их прочитать).
  • Регулярно обновляйте ID сессии после входа (session_regenerate_id()).

Пароли — это отдельная песня. Никогда не храните их в открытом виде. Используйте функцию password_hash() и password_verify(). Пример:

// Хеширование пароля при регистрации
$hash = password_hash($password, PASSWORD_BCRYPT);

// Проверка при входе
if (password_verify($input_password, $hash)) {
    echo 'Пароль верный';
}

Bcrypt — это медленный алгоритм, что усложняет подбор паролей. Не используйте md5 или sha1 — они слишком быстрые.

5. Дополнительные меры: валидация, настройки сервера и обновления

Валидация — это проверка данных на стороне сервера. Например, если ожидается email, используйте filter_var($_POST['email'], FILTER_VALIDATE_EMAIL). Не доверяйте клиентской проверке.

Настройки сервера тоже важны:

  • Отключите display_errors в production, чтобы не светить пути к файлам.
  • Установите правильные права на файлы (например, 644 для файлов, 755 для директорий).
  • Используйте open_basedir для ограничения доступа к файловой системе.

И самое главное — обновляйте PHP и библиотеки. Разработчики постоянно исправляют уязвимости. Не будьте тем, кто использует PHP 5.6 в 2025 году.

Правило: Безопасность — это процесс, а не одноразовое действие. Проверяйте код, используйте статические анализаторы (PHPStan, Psalm) и не забывайте про логирование.

Что в итоге?

Безопасность PHP-приложений — это не магия, а набор простых привычек. Используйте подготовленные запросы, экранируйте вывод, внедряйте CSRF-токены, правильно храните пароли и обновляйте зависимости. Начните с малого — хотя бы с одного пункта из этой статьи. Ваши пользователи скажут спасибо. А хакеры пойдут искать другую цель.

Студия WNDER