Найдите и исправьте уязвимость SQL-инъекции в фрагменте PHP: $q="SELECT * FROM users WHERE login='".$_POST['login']."' AND pass='".$_POST['pass']."'"; $res=mysql_query($q); — опишите безопасное переписывание, меры контроля ошибок и тесты на наличие других векторов атаки
Коротко: уязвимость — конкатенация входных данных в SQL (SQL‑инъекция) и использование устаревших mysql_*; решение — параметризованные запросы (prepared statements), хеширование паролей и безопасная обработка ошибок. Безопасное переписывание (рекомендуется PDO + password_hash/verify): <?php // Настройка PDO (обязательно charset=utf8mb4) $pdo = new PDO( "mysql:host=DB_HOST;dbname=DB_NAME;charset=utf8mb4", DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, ] ); $login = trim($_POST['login'] ?? ''); $pass = $_POST['pass'] ?? ''; // Простая валидация if ($login === '' || $pass === '') { http_response_code(400); echo 'Invalid input'; exit; } try { // Параметризованный запрос (нет конкатенации) $stmt = $pdo->prepare('SELECT id, password_hash FROM users WHERE login = :login LIMIT 1'); $stmt->execute([':login' => $login]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user && password_verify($pass, $user['password_hash'])) { // Успешная аутентификация session_regenerate_id(true); $_SESSION['user_id'] = $user['id']; echo 'OK'; } else { // Нельзя указывать, что именно не так http_response_code(401); echo 'Unauthorized'; } } catch (Exception $e) { // Логируем подробности на сервере, пользователю даём общее сообщение error_log('DB error: ' . $e->getMessage()); http_response_code(500); echo 'Server error'; } ?>
Замечания: - Пароли хранятся как хеш: при регистрации используйте `password_hash($pass, PASSWORD_DEFAULT)`, проверка — `password_verify`. - Отключите эмуляцию prepared statements: `PDO::ATTR_EMULATE_PREPARES => false`. - Установите кодировку соединения `utf8mb4` чтобы избежать проблем с обходом фильтров. - Не используйте mysql_* (устарело и небезопасно). Меры контроля ошибок и безопасности: - Логирование ошибок на сервере (error_log или централизованный лог), показывать пользователю только общие сообщения. - Использовать транзакции там, где нужно целостность. - Принцип наименьших привилегий для DB‑пользователя (только нужные права). - Ограничение длины и допустимых символов входных полей (например, максимальная длина логина). - Защита от брутфорса: rate limiting, капча или блокировка после нескольких неудач. - Защита сессий: HTTPS, HttpOnly и Secure для cookie, session_regenerate_id. - Периодическое обновление хешей паролей (если алгоритм устарел) через password_needs_rehash. - Проверять и параметризовать все запросы (включая INSERT/UPDATE/DELETE). Для SQL‑идентификаторов (ORDER BY, column names) применять белые списки вместо параметров. Тесты на наличие SQL‑инъекций и других векторов: - Ручные payloadы в полях логина/пароля: например - "' OR '1'='1' -- " - "admin' -- " - "'; DROP TABLE users; -- " (ввод этих строк должен не приводить к успешной авторизации и не ломать базу). - Автоматические сканеры: sqlmap, OWASP ZAP, Burp Suite — попытаться найти инъекции. - Code‑review / grep по проекту: искать конкатенации запросов, mysql_query, mysqli_query, exec/` . PHP‑файлы с динамическим SQL. - Тестировать другие точки ввода: заголовки, куки, JSON‑body, параметры URL. - Инструменты статического анализа и SAST (например, RIPS, SonarQube). - Тесты на XSS/CSRF/Session Fixation, так как инъекция — не единственная угроза. - Нагрузочное тестирование и проверки логики блокировок при попытках перебора паролей. Кратко: перепишите на подготовленные запросы, используйте корректное хранение паролей, логируйте ошибки локально, применяйте принцип наименьших привилегий и протестируйте приложение автоматическими и ручными средствами на инъекции и смежные уязвимости.
Безопасное переписывание (рекомендуется PDO + password_hash/verify):
<?php
// Настройка PDO (обязательно charset=utf8mb4)
$pdo = new PDO(
"mysql:host=DB_HOST;dbname=DB_NAME;charset=utf8mb4",
DB_USER,
DB_PASS,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]
);
$login = trim($_POST['login'] ?? '');
$pass = $_POST['pass'] ?? '';
// Простая валидация
if ($login === '' || $pass === '') {
http_response_code(400);
echo 'Invalid input';
exit;
}
try {
// Параметризованный запрос (нет конкатенации)
$stmt = $pdo->prepare('SELECT id, password_hash FROM users WHERE login = :login LIMIT 1');
$stmt->execute([':login' => $login]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($pass, $user['password_hash'])) {
// Успешная аутентификация
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
echo 'OK';
} else {
// Нельзя указывать, что именно не так
http_response_code(401);
echo 'Unauthorized';
}
} catch (Exception $e) {
// Логируем подробности на сервере, пользователю даём общее сообщение
error_log('DB error: ' . $e->getMessage());
http_response_code(500);
echo 'Server error';
}
?>
Замечания:
- Пароли хранятся как хеш: при регистрации используйте `password_hash($pass, PASSWORD_DEFAULT)`, проверка — `password_verify`.
- Отключите эмуляцию prepared statements: `PDO::ATTR_EMULATE_PREPARES => false`.
- Установите кодировку соединения `utf8mb4` чтобы избежать проблем с обходом фильтров.
- Не используйте mysql_* (устарело и небезопасно).
Меры контроля ошибок и безопасности:
- Логирование ошибок на сервере (error_log или централизованный лог), показывать пользователю только общие сообщения.
- Использовать транзакции там, где нужно целостность.
- Принцип наименьших привилегий для DB‑пользователя (только нужные права).
- Ограничение длины и допустимых символов входных полей (например, максимальная длина логина).
- Защита от брутфорса: rate limiting, капча или блокировка после нескольких неудач.
- Защита сессий: HTTPS, HttpOnly и Secure для cookie, session_regenerate_id.
- Периодическое обновление хешей паролей (если алгоритм устарел) через password_needs_rehash.
- Проверять и параметризовать все запросы (включая INSERT/UPDATE/DELETE). Для SQL‑идентификаторов (ORDER BY, column names) применять белые списки вместо параметров.
Тесты на наличие SQL‑инъекций и других векторов:
- Ручные payloadы в полях логина/пароля: например
- "' OR '1'='1' -- "
- "admin' -- "
- "'; DROP TABLE users; -- "
(ввод этих строк должен не приводить к успешной авторизации и не ломать базу).
- Автоматические сканеры: sqlmap, OWASP ZAP, Burp Suite — попытаться найти инъекции.
- Code‑review / grep по проекту: искать конкатенации запросов, mysql_query, mysqli_query, exec/` . PHP‑файлы с динамическим SQL.
- Тестировать другие точки ввода: заголовки, куки, JSON‑body, параметры URL.
- Инструменты статического анализа и SAST (например, RIPS, SonarQube).
- Тесты на XSS/CSRF/Session Fixation, так как инъекция — не единственная угроза.
- Нагрузочное тестирование и проверки логики блокировок при попытках перебора паролей.
Кратко: перепишите на подготовленные запросы, используйте корректное хранение паролей, логируйте ошибки локально, применяйте принцип наименьших привилегий и протестируйте приложение автоматическими и ручными средствами на инъекции и смежные уязвимости.