SQL-инъекции — один из самых опасных видов атак, когда злоумышленник может выполнить произвольный SQL-код через уязвимые параметры приложения. Вот профессиональные методы защиты.
PDO (PHP Data Objects):
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => $userInput]);
$results = $stmt->fetchAll();
MySQLi:
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$stmt = $mysqli->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bind_param('i', $userInput); // 'i' для integer
$stmt->execute();
$result = $stmt->get_result();
Пример с Laravel Eloquent:
User::where('email', $request->email)->first();
Пример с Doctrine DBAL:
$queryBuilder = $connection->createQueryBuilder();
$queryBuilder
->select('*')
->from('users')
->where('email = ?')
->setParameter(0, $email);
Фильтрация:
$cleanId = filter_var($inputId, FILTER_VALIDATE_INT);
if ($cleanId === false) {
throw new InvalidArgumentException('Invalid ID');
}
Валидация email:
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
die('Invalid email format');
}
Настройте пользователя БД с ограниченными правами:
Для MySQLi (менее предпочтительный способ):
$safeInput = $mysqli->real_escape_string($userInput);
$query = "SELECT * FROM users WHERE name = '$safeInput'";
Пример вызова:
$stmt = $pdo->prepare("CALL GetUserByEmail(?)");
$stmt->execute([$email]);
try {
// Валидация
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
if (!$email) {
throw new InvalidArgumentException('Invalid email');
}
// Подготовленное выражение
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? LIMIT 1');
$stmt->execute([$email]);
$user = $stmt->fetch();
if (!$user) {
// Логирование попытки входа
logFailedAttempt($_SERVER['REMOTE_ADDR'], $email);
}
} catch (PDOException $e) {
error_log($e->getMessage());
showGenericError();
}
Конкатенация строк запроса:
$query = "SELECT * FROM users WHERE id = " . $_GET['id']; // ОПАСНО!
Использование устаревших функций:
mysql_query("SELECT * FROM users WHERE name = '".mysql_real_escape_string($name)."'"); // Ненадежно
Динамические имена таблиц/колонок:
$query = "SELECT * FROM " . $_GET['table']; // Очень опасно
// Решение: белый список допустимых значений
$allowedTables = ['users', 'products'];
if (!in_array($_GET['table'], $allowedTables)) {
die('Invalid table');
}
лучшая защита от SQL-инъекций — использование подготовленных выражений (PDO/MySQLi) или ORM. Дополнительно применяйте валидацию входных данных, принцип минимальных привилегий и другие защитные меры. Никогда не доверяйте пользовательскому вводу и не используйте конкатенацию для построения SQL-запросов.