Руководства по безопасности
Публичный доступ к облачному хранилищу: почему данные могут утечь даже при включённом Block Public Access
Утечки из бакетов — это ошибки настройки, а не взлом. AWS прямо пишет, что Block Public Access не меняет существующие политики и ACL, поэтому публичные настройки остаются под блокировкой. Как проверить и по-настоящему исправить.
Утечки из объектного хранилища обычно обходятся без взлома. Никто не проникал в систему, учётные данные не украдены, в журналах нет ничего необычного. Просто настройка сделала данные публичными.
Почему данные утекают, хотя никто не взламывал
Вторжение
уязвимость или учётные данные → проникновение → вынос данных
обновления, аутентификация и мониторинг — каждый может это остановить
Ошибка настройки (публичный бакет)
знать (или угадать) URL → скачать
не «аутентификацию обошли», а аутентификация вообще не требовалась
Такой тип трудно заметить, потому что доступ не выглядит незаконным. Злоумышленник отправляет обычный GET на действительно публичный адрес, и системам обнаружения вторжений и анализу журналов почти не за что зацепиться. Это та же проблема, что и то, что нельзя держать в публичной папке, только в хранилище, а не на сервере.
Каждая из четырёх настроек блокирует своё
S3 Block Public Access — это четыре независимые настройки, которые можно включать в любом сочетании. Названия похожи, и их часто считают одним переключателем, но каждая блокирует своё.
- BlockPublicAcls
- Попытки назначить новый публичный ACL завершаются ошибкой (
PutBucketAcl,PutObjectAclилиPutObjectс публичным ACL). Существующие политики и ACL не меняются, поэтому уже назначенный публичный ACL остаётся - IgnorePublicAcls
- S3 игнорирует все публичные ACL бакета и его объектов.
PutObjectс публичным ACL всё равно выполняется (в этом отличие от BlockPublicAcls). Существующие ACL не удаляются, и назначать новые публичные ACL не запрещено - BlockPublicPolicy
- Отклоняет политику бакета, разрешающую публичный доступ (
PutBucketPolicyи связанные вызовы для точек доступа). На существующие политики не влияет - RestrictPublicBuckets
- Ограничивает доступ к бакету с публичной политикой сервисными принципалами AWS и авторизованными пользователями аккаунта-владельца. Блокирует межаккаунтный доступ (кроме сервисных принципалов AWS), включая непубличное делегирование конкретному аккаунту
Общее свойство всех четырёх, которое почти все упускают
Обратите внимание: в каждом пункте выше сказано, что существующие политики и ACL не меняются. Документация прямо называет последствие: «Block public access settings don't alter existing policies or ACLs. Therefore, removing a block public access setting causes a bucket or object with a public policy or ACL to again be publicly accessible» (настройки не меняют существующие политики и ACL, поэтому после снятия блокировки бакет или объект с публичной политикой или ACL снова становится публично доступным).
Значит, включение блокировки не убрало опасность. Оно лишь закрывает доступ на время, а публичные политики и ACL остаются. Кто-то временно снял блокировку для проверки, данные скопировали в другой аккаунт, diff в Terraform откатил настройку — и данные снова публичны. Целевое состояние — «не публично при выключенной блокировке», а не «блокировка включена».
«Публичным» считается больше, чем вы думаете
Вы можете считать бакет закрытым, а S3 при этом оценит его как публичный.
Считается публичным
・ACL, дающий права AllUsers или AuthenticatedUsers; второе означает всех владельцев аккаунта AWS, а не всех сотрудников вашей компании
・Политика бакета, где принципалы указаны значениями с подстановочным знаком или переменной политики
・Слишком широкий диапазон aws:SourceIp (шире /8 для IPv4, шире /32 для IPv6, частные диапазоны не считаются)
S3 сначала считает политику бакета публичной, а затем проверяет, можно ли признать её непубличной. Если однозначности нет, она считается публичной.
Считается непубличным
Политика, ограничивающая доступ фиксированными значениями без подстановочных знаков: принципал, набор блоков CIDR, aws:SourceArn, aws:SourceVpc, aws:SourceVpce, aws:SourceOwner, aws:SourceAccount и т. д.
Пример из самой документации: aws:SourceVpc со значением vpc-* — публично, а с фиксированным значением вроде vpc-91237329 — нет. «Я сузил» и «я сузил до фиксированного значения» — две стороны этой оценки.
Включайте блокировку на уровне аккаунта, а не бакета
Документация рекомендует применять BlockPublicPolicy на уровне аккаунта, потому что политика бакета может разрешить пользователям менять настройки блокировки этого бакета.
Только на уровне бакета
тот, кто может менять политику бакета → вставляет политику, отключающую блокировку → бакет можно сделать публичным
На уровне аккаунта
даже если политику бакета переписали, S3 блокирует публичную политику
Если настройки точки доступа, бакета и аккаунта различаются, S3 применяет самое строгое сочетание. Побеждает более строгая настройка, поэтому ограничение на уровне выше (аккаунт) нельзя ослабить ниже. Это минимум привилегий в применении к хранилищу.
В каком порядке исправлять
Посмотрите, что публично, прежде чем скрывать
Если сначала включить блокировку, доступ закроется, но одновременно вы потеряете возможность увидеть, что было открыто. Именно это описано как назначение BlockPublicAcls: защита от публичного доступа «while allowing you to audit, refine, or otherwise alter the existing policies and ACLs» (с возможностью проверить, уточнить или иначе изменить существующие политики и ACL). У AWS есть IAM Access Analyzer for S3: он показывает бакеты, чьи ACL или политики дают публичный доступ, и для каждой находки сообщает источник и уровень доступа. Сначала проведите инвентаризацию там.
Включите все четыре настройки на уровне аккаунта
AWS рекомендует включить все четыре настройки блокировки для аккаунта (и для каждого бакета — это проверяет контроль S3.8 в Security Hub). Сначала убедитесь, что приложения работают без публичного доступа. Если что-то действительно его требует, например хостинг статического сайта, настройте этот случай отдельно, а не отказывайтесь от контроля везде.
Действительно удалите публичные ACL и политики (самый важный шаг)
Блокировка не удаляет существующие публичные политики и ACL. Вернитесь к инвентаризации из шага 1 и удалите или перепишите их. Только тогда вы в состоянии «не публично при выключенной блокировке». Большинство команд останавливаются на шаге 2, и это главная мысль статьи.
Для бакетов, которые должны быть публичными, контролируйте содержимое
Если публичный доступ действительно нужен, разделите хранилище так, чтобы в публичном бакете лежало только то, что можно показывать всем. Резервные копии, дампы баз данных и списки клиентов не хранятся в одном бакете с публикуемыми файлами. От того, что вы кладёте в бакет, зависит, сколько из него может утечь. Та же логика для сервера — в статье как защитить .env на виртуальном хостинге.
Не полагайтесь на имя файла
«Никто не знает URL» — это не контроль доступа (та же проблема, что и угадываемые идентификаторы). Неугадываемое имя — дополнительная защита, а не замена проверке прав. Если нужно временно поделиться файлом, используйте то, что истекает само, — подписанный URL с ограниченным сроком действия, — и оставьте публичный доступ закрытым.
Позиция сайта: ошибки настройки исчезают, только когда состояние можно проверить
Публичные бакеты появляются снова и снова не из-за небрежности людей, а потому, что состояние не видно. В отличие от прав на файл или настройки сервера, публичность хранилища складывается из четырёх слоёв — политика, ACL, настройка аккаунта, точка доступа, — и ни один из них по отдельности не даёт ответа. Наша позиция для таких областей — поручить оценку сочетания машине, а не человеческому вниманию: ограничивать на уровне выше, чтобы ниже нельзя было ослабить, и регулярно повторять инвентаризацию инструментом, который сам выносит вердикт «публично / не публично». «Быть внимательным» — не мера защиты. К тому же выводу мы приходим и для зависимостей (как начать работать с osv-scanner).
Источники (первичные)
- Amazon Web Services, «Blocking public access to your Amazon S3 storage» (Amazon S3 User Guide) — docs.aws.amazon.com (поведение четырёх настроек, утверждение, что блокировка не меняет существующие политики и ACL, определение «публичного» и причина рекомендации применять настройки на уровне аккаунта — всё из этого документа)
Что почитать дальше
- Размещение файлов: что нельзя держать в публичной папке / как защитить .env на виртуальном хостинге
- Учётные данные: чем опасны .env и API-ключи / SSH-ключи и минимум привилегий
- Инвентаризация: чек-лист инвентаризации ресурсов
- Та же схема «утечка из-за настройки»: захват поддомена и висячие записи DNS
FAQ
QЕсли Block Public Access включён, я в безопасности?
Сейчас снаружи ничего не доступно, но опасность не исчезла. В документации AWS сказано, что настройки блокировки публичного доступа не меняют существующие политики и ACL, поэтому после снятия блокировки бакет или объект с публичной политикой или ACL снова становится публично доступным. Публичные политики и ACL остаются на месте под блокировкой. Нужно состояние не «блокировка включена», а «ничего не было бы публичным и без блокировки», то есть удалить сами публичные политики и ACL.
QВключать настройки для каждого бакета или для всего аккаунта?
Для аккаунта. В описании BlockPublicPolicy документация объясняет почему: политика бакета может разрешить пользователям менять настройки блокировки этого бакета, поэтому любой, кто может изменить политику бакета, может вставить политику, отключающую блокировку. Если настройка включена для всего аккаунта, S3 блокирует публичные политики, даже если пользователь изменит политику бакета. Настройку на уровне бакета могут снять те, кто может редактировать политики бакета.
QЧто именно считается «публичным»?
Больше, чем обычно думают. ACL публичен, если даёт права предопределённым группам AllUsers или AuthenticatedUsers, а AuthenticatedUsers — это все владельцы аккаунта AWS, а не все сотрудники вашей компании. Для политик бакета S3 сначала считает политику публичной, а затем проверяет, можно ли признать её непубличной. Это возможно, только если доступ ограничен фиксированными значениями без подстановочных знаков и переменных политики. Политика с aws:SourceIp и очень широким диапазоном (шире /8 для IPv4) тоже считается публичной.
QБезопасны ли новые бакеты по умолчанию?
В документации сказано, что по умолчанию новые бакеты, точки доступа и объекты не разрешают публичный доступ, но пользователи могут изменить политики бакета, политики точек доступа или права объектов, чтобы его разрешить. То есть по умолчанию всё безопасно, и почти все инциденты случаются там, где кто-то намеренно или временно, ради какой-то работы, ушёл от этого состояния. Не полагайтесь на значение по умолчанию: нужны и контроль, который нельзя отключить локально (блокировка на уровне аккаунта), и способ увидеть, что что-то изменилось.