🧱 Суть
Безопасность веб-приложения – это защита от ситуаций, когда пользователь может:
- выполнить чужой код
- получить доступ к чужим данным
- изменить действия без разрешения
- повлиять на работу сервера
В PHP основные угрозы, с которыми нужно знать базовый уровень:
- SQL Injection – внедрение SQL-кода через запросы к БД
- XSS – выполнение чужого JavaScript в браузере пользователя
- CSRF – выполнение действий от имени пользователя без его согласия
Схема:
Пользователь
|
↓
PHP-приложение
|
├── База данных → SQL Injection
|
├── HTML → XSS
|
└── Запросы → CSRF💻 Код
SQL Injection
Что это
SQL Injection – атака, при которой пользовательские данные попадают внутрь SQL-запроса и изменяют его логику.
Проблемный код:
$id = $_GET['id'];
$sql = "
SELECT *
FROM users
WHERE id = $id
";Обычный запрос:
?id=5Получается:
SELECT *
FROM users
WHERE id = 5Но злоумышленник может отправить:
?id=5 OR 1=1И получить:
SELECT *
FROM users
WHERE id = 5 OR 1=1Условие всегда истинно.
Защита
Использовать подготовленные запросы:
$stmt = $pdo->prepare(
"
SELECT *
FROM users
WHERE id = ?
"
);
$stmt->execute([$id]);Теперь данные не могут стать частью SQL-кода.
Правила
Использовать:
PDOprepare()execute()
Не использовать:
$sql = "SELECT * FROM users WHERE id=$id";XSS (Cross-Site Scripting)
Что это
XSS – атака, при которой пользовательский код попадает в HTML-страницу и выполняется в браузере другого пользователя.
Пример:
Пользователь вводит:
<script>
alert('hack')
</script>Если вывести это напрямую:
echo $_POST['comment'];браузер выполнит JavaScript.
Где возникает XSS
Частые места:
- комментарии
- профили пользователей
- сообщения
- поиск
- любые поля ввода
Опасный код:
echo $username;Если $username содержит HTML:
<img src=x onerror=alert(1)>код выполнится.
Защита от XSS
Экранирование HTML
Использовать:
htmlspecialchars();Пример:
echo htmlspecialchars(
$username,
ENT_QUOTES,
'UTF-8'
);Теперь:
<script>alert(1)</script>превратится в:
<script>alert(1)</script>Браузер покажет текст, а не выполнит код.
Правило
Данные пользователя нельзя выводить напрямую.
Плохо:
echo $userInput;Хорошо:
echo htmlspecialchars($userInput);XSS в JavaScript
Проблема существует и на фронтенде:
Опасно:
element.innerHTML = userInput;Безопаснее:
element.textContent = userInput;CSRF (Cross-Site Request Forgery)
Что это
CSRF – атака, когда злоумышленник заставляет пользователя выполнить действие на сайте, где он уже авторизован.
Например:
Пользователь вошёл в банк:
bank.comУ него есть cookie:
session=abc123Он открывает вредный сайт:
evil.comТам есть:
<form action="bank.com/transfer">
<input name="amount" value="10000">
</form>Браузер автоматически отправляет cookie.
Банк думает:
“Это настоящий пользователь”
Защита от CSRF
- CSRF-токен
Сервер создаёт уникальный токен:
<input
type="hidden"
name="csrf"
value="a8f92..."
>При отправке:
Форма
+
ТокенСервер проверяет:
if ($token !== $_SESSION['csrf']) {
die('Invalid request');
}- SameSite Cookies
Современные браузеры поддерживают:
setcookie(
'session',
$value,
[
'samesite' => 'Strict'
]
);Cookie не отправляется при подозрительных запросах.
Общие правила безопасности PHP
- Проверять входные данные
Все данные пользователя потенциально опасны:
$_GET
$_POST
$_COOKIE
$_FILESНужно проверять:
- тип
- длину
- формат
- допустимые значения
Пример:
if (!filter_var(
$email,
FILTER_VALIDATE_EMAIL
)) {
die('Invalid email');
}- Не доверять клиенту
HTML:
<input maxlength="20">не является защитой.
Пользователь может отправить запрос вручную:
username=оченьдлиннаястрокаПроверка должна быть на сервере.
- Не показывать ошибки пользователю
Плохо:
echo $exception->getMessage();Пользователь может увидеть:
SQL connection failed
Table users missingЛучше:
log_error($exception);
echo "Server error";- Использовать HTTPS
Без HTTPS злоумышленник может перехватить:
- cookies
- токены
- данные формы
- Хранить пароли правильно
Нельзя:
$password = "123456";или:
password = "123456"Использовать:
$passwordHash = password_hash(
$password,
PASSWORD_DEFAULT
);Проверка:
password_verify(
$password,
$hash
);Частые ошибки
Выводить данные напрямую
Плохо:
echo $_GET['name'];Правильно:
echo htmlspecialchars(
$_GET['name']
);Склеивать SQL
Плохо:
$sql =
"SELECT * FROM users WHERE id="
.$id;Правильно:
$stmt = $pdo->prepare(
"SELECT * FROM users WHERE id=?"
);Верить скрытым полям формы
Плохо:
<input
type="hidden"
value="admin"
/>Пользователь может изменить его.
Хранить секреты в коде
Плохо:
$password = "database_password";Лучше:
.envи переменные окружения.
🎯 Вывод
- SQL Injection возникает из-за вставки данных пользователя в SQL-код
- защита →
PDO+ подготовленные запросы - XSS позволяет выполнить чужой JavaScript в браузере
- защита → экранирование через
htmlspecialchars() - CSRF заставляет пользователя выполнять действия без его ведома
- защита → CSRF-токены и безопасные cookies
- нельзя доверять данным клиента
- вся валидация должна быть на сервере
- ошибки нельзя показывать пользователю
- безопасность – это не одна функция, а набор правильных практик