Безопасные приемы в SQL. Введение
SQL — мощный язык для работы с данными. Эта статья — практический список приёмов безопасной
работы с SQL с примерами кода и чек-листами. В конце — свод правил.
К чему приводит небезопасный SQL
| Проблема | Риск | Решение |
|---|---|---|
| SQL-инъекция из-за конкатенации строк | Кража/модификация данных | Параметризация запросов/ORM, валидация |
| Избыточные права (GRANT ALL) | Случайные/злонамеренные изменения | Ролевые модели, наименьшие привилегии |
| Нет ограничений схемы | Неконсистентность, каскады ошибок | NOT NULL, CHECK, UNIQUE, FK |
| Нет шифрования | Перехват трафика, утечки | TLS, TDE/pgcrypto, KMS/Vault |
| Операции без WHERE | Массовые инциденты | WHERE, LIMIT, транзакции, RLS |
| Старые версии СУБД | Эксплуатация CVE | Обновления/патчи |
| Нет аудита/логов | Нельзя расследовать | Аудит, централизованный логинг |
Антипаттерны и безопасные альтернативы
| Небезопасно | Безопасно | Комментарий |
|---|---|---|
| | Только параметризация, никаких конкатенаций. |
| | Минимально необходимые права. |
| | Запрашивайте только нужные поля. |
| | Всегда с WHERE и поэтапно. |
| | Пароли — только хэш + соль. |
Параметризация во всех слоях
cur.execute("SELECT * FROM users WHERE email = %s", (email,))
await client.query("SELECT * FROM users WHERE id = $1", [id]);
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id=?");
ps.setInt(1, id);
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute([':name' => $_GET['name']]);
Роли и права
CREATE ROLE app_ro; GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_ro;
CREATE ROLE app_rw; GRANT app_ro TO app_rw; GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_rw;
GRANT app_rw TO app_user;
Ограничения схемы
CREATE TABLE accounts (
id BIGSERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
password_hash BYTEA NOT NULL
);
Чек-лист правил безопасной работы
- Параметризация запросов, никаких конкатенаций.
- Минимально необходимые права и роли.
- Ограничения схемы: NOT NULL, CHECK, UNIQUE, FK.
- Операции только с WHERE/LIMIT, транзакции.
- Шифрование соединений и конфиденциальных данных.
- Хранение секретов в KMS/Vault, не в коде.
- Логи и аудит, алерты на аномалии.
- Регулярные обновления СУБД/драйверов.
- Миграции под контролем, проверка бэкапов.
- Изоляция окружений.