PostgreSQL

Безопасность PostgreSQL

2019. Capital One. S3 bucket с данными 100 миллионов клиентов. Доступ через EC2 с overprivileged IAM role. SQL-инъекция → AWS metadata → IAM credentials → S3 full access. Если бы PostgreSQL использовал минимальные привилегии + RLS: SQL-инъекция читает только данные текущего пользователя, не всех 100M. Security in depth - принцип минимальных привилегий спасает даже при наличии уязвимости.

  • **Supabase** - RLS как центральная концепция: каждый проект обязан настроить RLS перед production. Документация показывает паттерны multi-tenant RLS для SaaS
  • **Stripe** - separate roles per microservice: payments-service имеет доступ только к таблице payments, billing-service - к billing. SQL-инъекция в одном сервисе не компрометирует другие
  • **AWS RDS** - принудительный SSL, параметрические группы безопасности, IAM authentication вместо паролей, automatic rotation credentials

Roles и GRANT: минимальные привилегии

**PostgreSQL использует role-based access control (RBAC).** Role = пользователь или группа. Принцип минимальных привилегий: каждое приложение имеет роль только с нужными правами. Не давать SUPERUSER и даже CREATE DATABASE без необходимости.

**Никогда не давать приложению SUPERUSER.** SUPERUSER обходит все проверки безопасности включая RLS. SQL-инъекция в приложении с SUPERUSER = полный доступ к серверу. Минимальный набор прав: CONNECT, USAGE schema, SELECT/INSERT/UPDATE/DELETE на нужные таблицы.

Приложение использует роль app_user. SQL-инъекция позволяет выполнить `DROP TABLE users`. app_user имеет только SELECT, INSERT, UPDATE, DELETE. Что произойдёт?

Row-Level Security: изоляция данных

**Row-Level Security (RLS)** - политики на уровне строк. Каждый пользователь видит только строки, проходящие политику. Прозрачно для приложения: один SELECT, PostgreSQL автоматически добавляет фильтр. Идеально для multi-tenant SaaS: одна таблица, каждый клиент видит только свои данные.

**RLS + PgBouncer**: при transaction mode server_reset_query=DISCARD ALL очищает SET app.current_user_id. Нужно устанавливать контекст в каждой транзакции или использовать session mode. Supabase решает это через JWT в заголовке запроса и специальный middleware.

RLS включён на таблице `documents`. SUPERUSER выполняет `SELECT * FROM documents`. Что происходит?

Шифрование данных: pgcrypto и прозрачное шифрование

**Шифрование данных в PostgreSQL** - несколько уровней. pgcrypto extension: шифрование отдельных столбцов в SQL. Transparent Data Encryption (TDE): шифрование файлов данных на уровне ОС. Шифрование in transit: SSL/TLS для всех соединений.

**pgcrypto шифрование в SQL** - ключ передаётся в SQL запросе, виден в pg_stat_activity и pg_log. Для production: ключи управлять через vault (HashiCorp Vault, AWS KMS), не хранить в коде. Или использовать application-level encryption до отправки в БД.

Данные зашифрованы через pgp_sym_encrypt с ключом 'hardcoded_key'. DBA получил доступ к pg_log. Что компрометирует данные?

SSL: шифрование транспорта

**SSL/TLS** шифрует данные в транзите между клиентом и PostgreSQL. Без SSL данные (включая пароли) передаются в открытом виде по сети. PostgreSQL поддерживает SSL из коробки: нужно сертификат + ключ. pg_hba.conf управляет требованиями SSL для разных клиентов.

**sslmode=prefer** (дефолт в libpq) - клиент пробует SSL, при отказе сервера переходит на нешифрованное соединение. Для production: sslmode=require или verify-full. Managed PostgreSQL (RDS, Cloud SQL, Supabase) требует SSL по умолчанию.

sslmode=prefer и сервер поддерживает SSL. Клиент подключился без SSL из-за ошибки в negotiation. Что произошло?

pg_audit: аудит действий

**pg_audit** (PostgreSQL Audit Extension) - детальное логирование SQL операций для compliance (PCI DSS, HIPAA, SOC2). Логирует какой пользователь, когда, какую команду выполнил на каком объекте. Встроенный log_statement слишком груб - pg_audit даёт структурированные записи.

**PCI DSS требует** аудита всего доступа к данным карточек (PAN, CVV). pg_audit на таблице `card_data` + централизованное хранение логов (CloudWatch, Splunk) + retention 12 месяцев = compliance без дополнительных инструментов.

Row-Level Security (RLS) и обычные GRANT привилегии - одно и то же, просто разные синтаксисы

GRANT работает на уровне объектов (таблица/схема). RLS - на уровне строк внутри таблицы. Они дополняют друг друга: GRANT = можно ли читать таблицу, RLS = какие строки видны

GRANT SELECT ON TABLE orders = читать любые строки таблицы. RLS policy = фильтр применяется к каждому запросу автоматически. Без RLS у всех пользователей с GRANT SELECT = полный доступ ко всем строкам. С RLS = видят только свои строки. Multi-tenant без RLS требует WHERE tenant_id = ? в каждом запросе - ошибка пропущенного WHERE = data leak

pgaudit.log = 'write'. Аналитик выполняет `SELECT * FROM payments`. Попадёт ли это в аудит лог?

Итоги

  • **Минимальные привилегии**: приложение получает только SELECT/INSERT/UPDATE/DELETE на нужные таблицы. SUPERUSER только для DBA. Миграционная роль отдельно
  • **RLS** - политики на уровне строк. Каждый видит только свои данные. Прозрачно для приложения. SUPERUSER обходит RLS
  • **pgcrypto** шифрует столбцы, но ключ в SQL попадает в логи. Ключи управлять через vault, не хардкодить
  • **SSL** обязателен в production: sslmode=require или verify-full. prefer = ненадёжный fallback без шифрования
  • **pg_audit** для compliance (PCI DSS, HIPAA): детальный аудит DDL/DML по пользователям и объектам

Связанные темы

Безопасность пронизывает всю архитектуру PostgreSQL:

  • Views и Materialized Views — security_barrier views - защита от утечки данных через оптимизацию предикатов. Альтернатива RLS для простых случаев
  • Мониторинг — pg_audit + мониторинг pg_stat_activity = полная картина кто и что делает в БД. Алерты на подозрительные паттерны
  • Миграции — DDL права в GRANT: миграционная роль отдельно от application role. Migrate без production SUPERUSER

Вопросы для размышления

  • SaaS приложение с 10K клиентов в одной таблице `data`. Без RLS: каждый запрос должен иметь `WHERE client_id = ?`. Что произойдёт если разработчик забудет WHERE в одном запросе? Как RLS устраняет этот класс ошибок?
  • Компания должна соответствовать HIPAA: аудит всего доступа к полю SSN в таблице `patients`. Как настроить pg_audit чтобы логировать только SELECT на это поле, не все SELECT на таблицу?
  • При SQL-инъекции атакующий может выполнить `COPY (SELECT ...) TO PROGRAM 'curl ...'`. Какие привилегии нужны для COPY TO PROGRAM? Как правильно настроить роли чтобы это было невозможно?

Связанные уроки

  • db-13-transactions
Безопасность PostgreSQL

0

1

Войти