4. Hardening: принцип наименьших привилегий
Hardening: Принцип наименьших привилегий
Даже если в Go-коде допущена досадная ошибка, масштаб ущерба можно существенно минимизировать правильной настройкой базы данных. Принцип «наименьших привилегий» (Least Privilege) гласит: каждый процесс должен иметь ровно столько прав, сколько ему необходимо для выполнения его задач, и ни капли больше.
Этот принцип сформулирован Джеромом Зальцером и Майклом Шредером ещё в 1975 году в их работе «The Protection of Information in Computer Systems», и за полвека он не утратил актуальности. В контексте веб-приложений Least Privilege означает: бэкенд, обслуживающий формы регистрации и поиска товаров, не должен иметь права удалять таблицы или читать системные каталоги — даже если в коде есть SQL-инъекция. Атакующий, пробивший Go-приложение через fmt.Sprintf, упирается в стенку при попытке выполнить DROP TABLE или прочитать pg_user — потому что у database-пользователя, под которым работает Go-приложение, просто нет таких прав.
Аналогия из физического мира: представь банк, где у каждого сотрудника есть карточка-пропуск с разными уровнями доступа. Кассир может зайти только в зону обслуживания клиентов; менеджер — в офис и хранилище наличных дневного оборота; директор — везде, кроме главного хранилища, куда есть доступ только у двух человек. Если злоумышленник украл карточку кассира, он не сможет добраться до сейфов — пропускной режим не пустит. Так же и database-пользователь Go-приложения: даже после успешной инъекции его «карточка» открывает только ограниченный набор операций.
Разберемся, как изолировать ваше приложение так, чтобы даже успешная инъекция не позволила хакеру удалить таблицы.
1. Механика: "Изоляция одного пользователя"
Ошибка многих новичков — использовать для веб-приложения пользователя с правами суперадмина. В этом случае хакер через SQLi может сделать всё, вплоть до DROP TABLE. Типичный сценарий: разработчик создаёт базу через createdb mydb под своим суперпользователем, копирует строку подключения в .env файл — и эта строка с правами суперюзера улетает в production. Удобно для разработки, катастрофа для безопасности.
Как это должно быть реализовано:
- Создаем отдельного пользователя
app_client. - Даем ему права только на
SELECT,UPDATEиINSERTдля нужных таблиц. - Полностью блокируем доступ к системным схемам, таким как
information_schemaилиpg_catalog.
2. Коды настройки (СУБД PostgreSQL/MySQL)
Сейчас увидим разницу между удобной (но опасной) и безопасной конфигурацией прав. Это первая строка обороны на уровне инфраструктуры — её настраивает DBA или DevOps-инженер при создании окружения, и для команды разработки это становится «прозрачным» защитным слоем: код продолжает работать как раньше, но при инциденте ущерб ограничен.
-- ❌ СМЕРТЕЛЬНО ОПАСНО: Дать все права приложению
GRANT ALL PRIVILEGES ON DATABASE secure_code_db TO app_user;
-- ✅ БЕЗОПАСНЫЙ ПОДХОД: Минимум прав
-- Читать только таблицу продуктов
GRANT SELECT ON products TO app_user;
-- Писать только в таблицу логов
GRANT INSERT ON web_logs TO app_user;
-- Запретить доступ к системным данным
REVOKE ALL ON SCHEMA information_schema FROM app_user;
3. Таблица "Ущерб" при разных правах в БД
| Привилегии в БД | Что сможет хакер через SQLi? |
|---|---|
| Superuser | 🔴 УДАЛИТЬ всё, вытащить пароли, RCE |
| Owner | 🔴 Вытащить все данные, изменить их |
| Least Priv. | 🟢 Только поиск товаров (что и делает сайт) |
4. Почему это критично для Go?
Даже идеальный Go-код может столкнуться с уязвимостью в сторонней библиотеке или редким «краевым случаем». Ограничение прав в базе — это ваш ПОСЛЕДНИЙ РУБЕЖ ЗАЩИТЫ (Defense in Depth). В реальной практике Defense in Depth — это многослойная архитектура: WAF на edge, валидация параметров на уровне Go-middleware, параметризованные запросы в SQL, ограниченные права у БД-пользователя, network policy запрещающая egress из БД-pod в интернет, мониторинг аномалий в SIEM. Каждый слой может быть пробит, но злоумышленнику нужно пробить ВСЕ для успешной атаки.
В Go вы просто указываете данные этого ограниченного пользователя в строке подключения:
// Логин app_client имеет минимум прав в базе
db, err := sql.Open("postgres", "postgres://app_client:pass@localhost/db")
Best practice: для микросервисной архитектуры создаётся отдельный database-пользователь под каждый сервис, и каждый из них имеет узкий набор прав только под свою предметную область. Сервис каталога — только SELECT на products, categories; сервис заказов — SELECT/INSERT/UPDATE на orders, order_items; сервис аналитики — только SELECT на read-replica с заранее настроенными агрегациями. Это паттерн «database per service» от Сэма Ньюмена, описанный в книге «Building Microservices». В Kubernetes секреты-credentials хранятся в HashiCorp Vault или Sealed Secrets, никогда в открытом виде в репозитории.
Дополнительная защита: PostgreSQL row-level security (RLS) добавляет фильтр прямо на уровне СУБД — например, «пользователь app_user видит только строки, где tenant_id = current_setting('app.tenant_id')». Даже если в Go-коде забыли добавить WHERE tenant_id = ?, RLS не пустит запрос за пределы tenant'а. Это особенно важно для multi-tenant SaaS-приложений, где утечка данных между клиентами означает потерю compliance-сертификации.
Инфраструктурная защита — это ваша страховка. Ограничение прав не исправляет баг в коде, но оно превращает потенциально фатальный взлом в локальную и поправимую проблему.
Соответствие стандартам: PCI-DSS требование 7 — «Restrict access to cardholder data by business need to know» прямо обязывает применять least privilege для всех систем, работающих с карточными данными. ISO 27001 Annex A.9.4.1 «Information access restriction». NIST SP 800-53 AC-6 «Least Privilege» — фундаментальное требование для всех федеральных систем США. GDPR Article 32 — «adequate technical measures» — регулятор смотрит, ограничены ли права у database-юзера приложения, если хочет понять, насколько серьёзны меры защиты данных.
Мы завершили блок разведки и hardening'а. После квиза нас ждет погружение в одну из самых коварных тем — слепые инъекции.
Продолжить чтение
Что бы прочитать модуль полностью, зарегистрируйтесь/войдите на платформу
Когда закончишь — отметь раздел, чтобы продолжить.