У каждого девятого приложения утекают ключи Supabase: рассказываем, как это происходит

BBetter Stack
컴퓨터/소프트웨어창업/스타트업AI/미래기술

Transcript

00:00:00В этом месяце вышел отчет: сканирование 20 000 инди-приложений показало, что в каждом девятом
00:00:04учетные данные Supabase были открыты прямо во фронтенд-коде.
00:00:08И речь не о логах сервера или приватных репозиториях.
00:00:11Они находятся в обычном JavaScript, который скачивает каждый посетитель.
00:00:14Причем эти приложения никто не взламывал — разработчики просто случайно выложили секрет в открытый доступ.
00:00:18Поясню: некоторые ключи и должны быть публичными.
00:00:21Проблема в самом процессе разработки, ведь из-за той же ошибки в браузер может попасть ключ,
00:00:25которому там вообще не место.
00:00:27У нас постоянно выходят новые видео.
00:00:28Не забудьте подписаться.
00:00:35Вот простая истина, которая многих ставит в тупик.
00:00:38Мы все об этом догадываемся, но в спешке об этом легко забыть.
00:00:41Когда вы помечаете переменную окружения как публичную, ваш сборщик считает, что она нужна
00:00:46в браузере, и добавляет ее в клиентский бандл.
00:00:50Next.js делает это через NEXT_PUBLIC, Vite — через VITE_, а SvelteKit использует
00:00:56префикс public.
00:00:57Слово “public” — это не метка безопасности, это буквально наклейка “отправить клиенту”.
00:01:01Теперь разберемся с особенностями Supabase.
00:01:04Одни ключи должны быть публичными (как anon или publishable), а другие — приватными,
00:01:10например service_role или секретные ключи.
00:01:12Если приватный ключ попадает в браузер... ну, вы сами понимаете, что будет.
00:01:17В этом случае Row Level Security (RLS) вас не спасет.
00:01:20В документации Supabase четко сказано, что сервисные ключи обходят RLS.
00:01:24Так что если этот ключ во фронтенде, вся ваша работа над политиками доступа теряет смысл.
00:01:29Позвольте мне показать на практике в моей «песочнице», как именно это происходит.
00:01:33Сначала я создал простое CRUD-приложение на Next.js и подключил к нему Supabase.
00:01:38Вот мой .env файл, и вот она — ошибка.
00:01:41Я поместил ключ в переменную с префиксом PUBLIC.
00:01:45Этот ключ публичный, так что он и должен быть виден.
00:01:48Но проблема в том, что через тот же NEXT_PUBLIC можно случайно отправить и приватный ключ.
00:01:53Я запустил npm run build, собрал проект и запустил приложение.
00:01:59Открываю Chrome.
00:02:00Быстро добавлю данные в нашу базу через приложение.
00:02:05Теперь я открываю скомпилированный JavaScript-бандл и ищу этот ключ.
00:02:10Вот он.
00:02:12URL и ключ лежат прямо внутри файла, который ваши пользователи только что загрузили
00:02:18в свой браузер.
00:02:19И заметьте: никакого взлома.
00:02:21Я просто нашел его, понимаете?
00:02:22Никто не использовал уязвимости.
00:02:24Это просто чтение того, что приложение само выложило в интернет.
00:02:25Если это видите вы, это увидит любой.
00:02:29Откройте инструменты разработчика, изучите JS-файлы и введите поиск.
00:02:32Больше ничего не нужно.
00:02:35И если вы надеетесь, что «никто не будет смотреть» — интернет полон людей и ботов,
00:02:36чья работа как раз и заключается в поиске таких вещей.
00:02:41Вот решение, которое действительно работает.
00:02:44Браузер должен обращаться только к вашему API.
00:02:47Ваш API работает на стороне сервера.
00:02:50Именно там должны храниться приватные ключи.
00:02:52Перенесите приватные операции в API-роуты или серверные функции.
00:02:54Клиент вызывает ваш эндпоинт, ваш эндпоинт обращается к Supabase. Затем пересоберите проект и проверьте бандл.
00:02:58Если ключ исчез из бандла — вы исправили проблему. Но не стоит на этом останавливаться,
00:03:03есть и другие меры предосторожности.
00:03:04Убедитесь, что RLS включен для всех таблиц, к которым обращается пользователь,
00:03:09и проверьте, что ваши политики работают именно так, как задумано.
00:03:11Уделите время тестированию.
00:03:16Мне кажется, об этом часто забывают.
00:03:18Теперь о том, как не допустить повторения ошибки. Обычно разработчики исправляют это один раз,
00:03:19а потом в спешке снова наступают на те же грабли.
00:03:21Установите «ограждения». Начните со сканирования секретов в CI,
00:03:26чтобы сборка падала, если ключ окажется там, где не должен.
00:03:28Внедрите правило при проверке PR: всё, что помечено NEXT_PUBLIC или VITE, по умолчанию считается публичным.
00:03:34И наконец, настройте ротацию ключей.
00:03:36Если есть хоть малейшее подозрение, что ключи утекли — просто смените их.
00:03:41Это лучше, чем гадать несколько дней, воспользуется ли ими кто-то.
00:03:42Что вы можете сделать прямо сейчас:
00:03:43Соберите приложение так, как вы его деплоите.
00:03:47Поищите в результатах сборки упоминания Supabase, JWT, service_secret или токены.
00:03:50Если нашли что-то приватное — считайте, что ключ скомпрометирован.
00:03:52Замените его и перенесите логику на сервер.
00:03:55Если из этого видео нужно запомнить только одну фразу, пусть это будет эта:
00:04:01Если ключ попал в бандл — он стал публичным.
00:04:05Увидимся в следующих видео.
00:04:08If you remember one line from this video, make it this.
00:04:11If it's in the bundle, it's public.
00:04:13We'll see you in another video.

Key Takeaway

Любой секретный ключ, попавший в клиентский бандл через публичные переменные окружения, считается общедоступным, что делает защиту базы данных неэффективной.

Highlights

Каждое девятое инди-приложение случайно раскрывает учетные данные Supabase во фронтенд-коде

Использование префиксов NEXT_PUBLIC или VITE_ автоматически включает переменные в клиентский бандл

Приватные ключи

Timeline

Масштаб проблемы и суть утечки

Согласно недавнему отчету, сканирование 20 000 приложений выявило критическую проблему безопасности в каждом девятом из них. Разработчики случайно публикуют учетные данные Supabase прямо в исходном коде фронтенда, доступном любому пользователю. Речь идет не о взломе серверов или краже данных из приватных репозиториев, а о простой невнимательности при разработке. Проблема заключается в том, что JavaScript-файлы, содержащие секреты, скачиваются браузером каждого посетителя сайта. Это создает огромную дыру в безопасности, так как конфиденциальная информация оказывается в открытом доступе.

Механизм работы переменных окружения

Спикер объясняет техническую сторону того, как секреты попадают в клиентскую часть приложения через сборщики кода. Популярные фреймворки, такие как Next.js, Vite и SvelteKit, используют специальные префиксы для маркировки публичных переменных. Например, использование префикса NEXT_PUBLIC или VITE_ дает сборщику команду включить эту переменную в итоговый бандл для браузера. Важно понимать, что слово "public" в названии переменной — это не инструмент безопасности, а техническая метка для передачи данных клиенту. Ошибка разработчика часто заключается в автоматическом добавлении этого префикса ко всем переменным без разбора их секретности.

Опасность утечки service_role и обход RLS

В экосистеме Supabase существует четкое разделение между публичными ключами (anon) и приватными сервисными ключами. Приватный ключ service_role обладает расширенными правами и предназначен исключительно для использования на стороне сервера. Главная опасность заключается в том, что этот ключ полностью игнорирует политики Row Level Security (RLS). Если такой ключ попадает во фронтенд, злоумышленник получает полный доступ к базе данных, и все настройки безопасности аннулируются. Спикер подчеркивает, что документация Supabase прямо предупреждает о недопустимости передачи сервисных ключей на клиентскую сторону.

Практическая демонстрация и поиск ключей

Автор наглядно демонстрирует процесс утечки на примере простого CRUD-приложения, созданного в учебных целях. После сборки проекта через команду npm run build, приватный ключ оказывается зашит внутри скомпилированного JavaScript-файла. Используя обычные инструменты разработчика в браузере Chrome, можно легко найти URL базы данных и секретный токен через поиск по строкам. Видео акцентирует внимание на том, что для получения доступа не требуются хакерские навыки или использование уязвимостей. Интернет постоянно сканируется ботами и людьми, которые ищут такие «подарки» в открытом коде приложений.

Способы исправления и архитектурные решения

Для устранения уязвимости необходимо изменить архитектуру взаимодействия с базой данных, исключив прямое обращение клиента к Supabase с приватными правами. Правильный подход подразумевает, что браузер обращается только к API-эндпоинтам, которые работают на защищенном сервере. Именно на стороне сервера должны храниться и использоваться все приватные ключи, выполняя роль посредника. После внесения изменений крайне важно повторно собрать проект и лично убедиться, что ключи исчезли из клиентского бандла. Также рекомендуется всегда держать RLS включенным для всех таблиц и тщательно тестировать политики доступа пользователей.

Предотвращение ошибок и финальные рекомендации

В заключительной части обсуждаются меры долгосрочной защиты, чтобы избежать повторения подобных инцидентов в будущем. Спикер советует внедрить автоматическое сканирование секретов в процесс CI/CD, чтобы сборка блокировалась при обнаружении ключей. В процессе ревью кода (PR) любые переменные с префиксами публичности должны подвергаться особому контролю со стороны команды. Также важным шагом является регулярная ротация ключей, особенно если возникло подозрение на их компрометацию. Финальный совет прост: соберите свое приложение прямо сейчас и поищите в коде слова "Supabase" или "JWT", чтобы убедиться в его безопасности. Главный урок видео — любая информация в бандле автоматически становится публичным достоянием.

Community Posts

No posts yet. Be the first to write about this video!

Write about this video