Skip to content
← Все статьи

Защита от SQL injection: prepared statements и ORM

Защита от SQL injection: prepared statements и ORM

SQL injection — классическая уязвимость из OWASP Top 10: Injection, которая даже в 2026 году регулярно всплывает в production-инцидентах. Одна строка ' OR '1'='1 в поле логина может обойти аутентификацию, украсть всю базу или дать RCE через UDF. В этой статье — типы SQLi, правильная защита через prepared statements, роль ORM, настройка least privilege и fallback-защита через WAF.

Как работает SQL injection

Классическая уязвимость — конкатенация пользовательского ввода в SQL-запрос:

// ❌ Уязвимо
$email = $_POST['email'];
$sql = "SELECT * FROM users WHERE email = '{$email}'";

// Атакующий подставляет: ' OR '1'='1
// Итог: SELECT * FROM users WHERE email = '' OR '1'='1' — вернёт всех

Более опасные payload: '; DROP TABLE users; --, UNION SELECT password, NULL FROM admin_users, blind SQLi через timing attacks.

Типы SQL injection

Главная защита: prepared statements

Prepared statements — разделение SQL-кода и данных на уровне протокола БД. Драйвер БД отправляет запрос-шаблон и параметры отдельно; никакая строка в параметре не может стать SQL-кодом.

PHP PDO

// ✅ Безопасно
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND is_active = ?');
$stmt->execute([$email, 1]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);

// ✅ Именованные параметры
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute([':email' => $email]);

Критично: отключить эмуляцию prepared в PDO — иначе параметры подставляются на уровне библиотеки строкой:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Node.js

// mysql2
const [rows] = await pool.execute(
  'SELECT * FROM users WHERE email = ? AND active = ?',
  [email, 1]
);

// pg
const { rows } = await client.query(
  'SELECT * FROM users WHERE email = $1',
  [email]
);

Python

# psycopg2
cur.execute('SELECT * FROM users WHERE email = %s', (email,))

# SQLAlchemy Core
stmt = text('SELECT * FROM users WHERE email = :email')
result = conn.execute(stmt, {'email': email})

Что нельзя параметризовать

Имена таблиц, колонок, направление сортировки (ASC/DESC) нельзя передать как параметр. Используйте whitelist:

$allowed = ['name', 'created_at', 'email'];
$sort = in_array($_GET['sort'] ?? '', $allowed, true) ? $_GET['sort'] : 'created_at';
$sql = "SELECT * FROM users ORDER BY {$sort}";

ORM как защита

Современные ORM (Prisma, Doctrine, Sequelize, SQLAlchemy ORM) по умолчанию используют prepared statements. Но опасны методы raw-запросов:

// Prisma — ❌ raw с интерполяцией
await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);

// ✅ Параметризованный tagged template
await prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;

Least privilege для БД-пользователя

Приложение не должно ходить в БД под root. Минимум для приложения:

GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app'@'localhost';
-- НЕ давать: DROP, CREATE, ALTER, FILE, SUPER, GRANT

Для read-only эндпоинтов — отдельный пользователь с SELECT only. Это превращает successful SQLi в отчёт вместо катастрофы.

WAF и мониторинг

WAF (ModSecurity + OWASP CRS, Cloudflare) блокирует типичные payload — подробнее в WAF гайде. Настройте алерты на:

Проверка

FAQ

Защищает ли mysql_real_escape_string? Слабо. Обходится через multibyte-набор символов (CVE-2006-7243) и не защищает внутри числовых контекстов. Только prepared statements.

Безопасен ли preg_match как фильтр? Нет — атакующий обойдёт любой blacklist. Whitelist ввода + параметризация — единственный workable подход.

Защищает ли ORM полностью? Да, пока вы не используете raw-методы. Проверяйте код на $queryRawUnsafe, db.raw(), Connection.execute().

Что с NoSQL (MongoDB)? Эквивалент — NoSQL injection через объекты $ne/$gt в JSON. Валидируйте тип: typeof user.email === 'string'.

Вывод

Три слоя: 1) prepared statements везде; 2) least privilege в БД; 3) WAF как сигнализация. Мониторьте endpoint'ы через enterno monitors и проверяйте security headers через Security Scanner. Связанное: XSS, rate limiting, WAF.

Проверьте ваш сайт прямо сейчас

Проверить →
Другие статьи: SEC
SEC
Миграция с HTTP на HTTPS: редиректы, mixed content, HSTS
15.04.2026 · 7 просм.
SEC
CORS: полное руководство по Access-Control-Allow
15.04.2026 · 2 просм.
SEC
Cookie Security: HttpOnly, Secure, SameSite, __Host-
15.04.2026 · 5 просм.
SEC
Защита от XSS атак: типы, эскейпинг, CSP, Trusted Types
15.04.2026 · 2 просм.