Безопасность спрашивают на любом PHP-собесе: SQL-инъекции, XSS, CSRF, пароли и сессии. Важно не только назвать атаку, но и объяснить механику и защиту.
SQL-инъекция
// уязвимо
$pdo->query("SELECT * FROM users WHERE email = '$email'");
// безопасно
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $email]);
Подготовленный запрос отделяет данные от SQL. Имена колонок и направление сортировки параметром не передать: их проверяют по белому списку. ORM параметризуют запросы сами, но сырые фрагменты (whereRaw, DB::raw) снова ваша ответственность.
XSS
Пользовательские данные выводят с экранированием по контексту:
<?= htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?>
Blade {{ }} и Twig экранируют автоматически, {!! !!} и |raw нет. Ссылки из пользовательских данных проверяют на схему (javascript: выполнится). strip_tags не защита. Дополнительный слой: заголовок Content-Security-Policy.
CSRF
Браузер прикладывает cookie к запросам с чужих сайтов. Защита: секретный токен в форме, сверяемый с сессией (во фреймворках включён по умолчанию), и cookie с SameSite=Lax. Метод POST сам по себе не защищает.
Пароли
$hash = password_hash($password, PASSWORD_DEFAULT); // bcrypt, можно PASSWORD_ARGON2ID
if (password_verify($input, $hash)) { ... }
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) { /* пересчитать */ }
MD5 и SHA-* для паролей не годятся: слишком быстрые. Токены генерируют random_bytes, сравнивают через hash_equals.
Сессии
- Cookie сессии:
HttpOnly,Secure,SameSite. - После входа
session_regenerate_id(true)против фиксации сессии. - Короткий срок жизни, выход уничтожает сессию.
- При нескольких серверах сессии в Redis, а не в файлах.
- Блокировка сессии: файловые сессии блокируются на время запроса, параллельные AJAX-запросы одного пользователя выстраиваются в очередь (
session_write_closeкак можно раньше).
Контроль доступа
Самая частая реальная уязвимость: проверили, что пользователь вошёл, но не проверили, что заказ его (IDOR). Права проверяют на каждом действии: политики Laravel, voters Symfony.
Другие атаки
- Массовое присваивание:
create($request->all())с пустым$guarded. Нужны$fillableи валидированные данные. - Загрузка файлов: тип по содержимому (
finfo), своё имя, хранение вне корня сайта. - unserialize внешних данных: PHP object injection. Используйте JSON.
- SSRF: загрузка по URL от пользователя на внутренние адреса.
- Обход каталога:
../в путях к файлам, нормализация и проверка базового каталога. - Секреты: в переменных окружения, не в репозитории.
composer auditдля зависимостей.
Частые ошибки
- Экранирование при сохранении вместо вывода.
- Чёрные списки «опасных» слов.
- Подробные ошибки в продакшене (
display_errors=On). - Сообщение «пароль неверный для такого email», раскрывающее существование аккаунта.
Что спросят на собесе
- Как защититься от SQL-инъекций и почему
addslashesне подходит? - Что такое XSS и CSRF, чем они отличаются и как защищаться?
- Как правильно хранить пароли?
- Какие настройки нужны сессиям и зачем
session_regenerate_id? - Что такое IDOR и массовое присваивание?