Редактируйте секреты до вставки
Отредактировать секрет — значит заменить учётные данные в тексте, ключ API, токен, пароль или закрытый ключ, маркером до того, как текстом поделятся, чтобы информация путешествовала без доступа. Это важно, потому что самый распространённый способ утечки секретов — не атака, а вставка: лог в тикет поддержки, файл конфигурации в чат, отладочная команда в сообщение на форуме. Эта статья объясняет, почему те вставки так трудно отменить, что сканер вроде редактора секретов может и не может обнаружить, и процесс — редактировать локально, делиться отредактированной копией, ротировать всё, что уже сбежало, — который не даёт услужливой вставке стать инцидентом.
Почему секреты оказываются в тикетах, чатах и логах
Никто не вставляет секрет нарочно. Вставляют то, что окружает секрет: лог ошибки, который случайно включает заголовки запроса, файл конфигурации, который случайно хранит пароль базы данных тремя разделами ниже, команду curl, скопированную из терминала, где токен сидит в заголовке Authorization. Поиск неисправностей работает на контексте, а учётные данные живут внутри контекста — вот почему службы поддержки, каналы чатов и трекеры задач тихо накапливают живые ключи, токены сессий и закрытые ключи, написанные осторожными людьми в спешке, которые смотрели на сообщение об ошибке, а не на заголовок над ним.
Принимающая система затем делает ту вставку постоянной способами, которых отправитель никогда не видит. Тикеты индексируются для поиска, пересылаются поставщикам, экспортируются в отчёты и хранятся годами; сообщения чатов推送тся на телефоны как уведомления, цитируются в ветках и суммируются ботами; логи отправляются в агрегаторы с их собственным хранением и собственными списками доступа. Секрет в одной из таких систем находится не в одном месте — он в каждой копии, резервной копии, предпросмотре и уведомлении, которые система сгенерировала, большинство из которых отправитель не может ни перечислить, ни тем более удалить. Эта асимметрия — секунда на вставку, нет надёжного способа отозвать — и есть вся причина, по которой редактирование должно происходить до вставки, на машине отправителя, а не как уборка после.
Что сканер может обнаружить: формы, контрольные суммы и структуру
Хорошая новость в том, что настоящие учётные данные сильно узорны, а сканирование по шаблонам детерминировано: тот же текст всегда даёт те же находки, без угадывающей модели между ними. Ключи поставщиков несут опубликованные формы — префиксы, фиксированные длины, ограниченные алфавиты, — поэтому ключ доступа AWS, токен GitHub, ключ Stripe или токен Slack можно узнать с первого взгляда, как человек узнаёт номер телефона в абзаце. Закрытые ключи объявляют о себе строками брони BEGIN и END, а JSON Web Token имеют жёсткую трёхсегментную структуру, первые два сегмента которой всегда начинаются одинаково, потому что всегда кодируют один и тот же вид JSON.
Две проверки держат слой шаблонов честным. Номера карт отмечаются, только когда проходят контрольную сумму Луна — арифметический тест, встроенный в каждый подлинный номер карты, который отделяет настоящие карты от куда большей популяции длинных чисел — заказов, счетов, временных меток, — которые им только подобны. А где формы перекрываются, конкретные шаблоны побеждают общие, так что известный ключ поставщика, присвоенный переменной, сообщается один раз, под его настоящим типом, с приложенными правильными инструкциями по ротации. Собственное сканирование секретов GitHub, первый источник ниже, работает по тому же принципу в масштабе платформы: партнёры публикуют форматы своих токенов, а платформа сопоставляет их точно. Локальный сканер — та же идея, выполненная в последний момент, когда она ещё может помочь, — ваш браузер, до того, как вы нажмёте «Отправить».
Что сканер не может обнаружить: энтропию и контекст
За пределами форм поставщиков обнаружение становится вероятностным. Общее правило может искать присваивания — имя вроде password или api_key рядом со значением — и требовать, чтобы значение выглядело случайным, измеренным энтропией Шеннона. Это ловит сгенерированный ключ, присвоенный переменной, и игнорирует слово password в предложении, но граница — это суждение в одежде числа: сильный человеческий пароль и слабый машинный ключ живут на одной шкале, настоящий секрет, набранный как фраза, получает низкую оценку, а случайно выглядящий хэш сборки без слов-заполнителей получает высокую. Энтропия говорит вам, что строка удивительна; она не может сказать вам, что строка — учётные данные.
Контекст — большее слепое пятно, потому что почти всё, что делает значение опасным, находится вне значения. Сессионная cookie — просто буквы и цифры, пока вы не узнаете, какой сервис она отпирает. Пароль базы данных выглядит безобидно внутри строки подключения, распределённой между тремя переменными окружения, а одноразовый код чувствителен только десять минут. Сканеры также не видят сквозь структуру: секрет, перенесённый через две строки лога, закодированный в base64 внутри блоба или сфотографированный в изображение, невидим для текстовых шаблонов, какими бы хорошими они ни были. Честный итог таков: сканер надёжно ловит документированное, хорошо сформированное большинство — а предпросмотр, который он вам показывает, с подсвеченными на месте совпадениями, всё же заслуживает вашего собственного десятисекундного просмотра, потому что ваши глаза знают контекст, которого шаблоны знать не могут.
Есть ещё один класс, к которому сканер намеренно слеп, и он находится прямо рядом с ловушкой: заполнители. Значения документации — содержащие слова вроде example, test, dummy или your- — исключаются, чтобы руководства и учебные материалы не зажигали таблицу находок. Но каждое исключение — это дверь: настоящий ключ, случайно содержащий одно из этих слов, или ленивый настоящий пароль, установленный в похожее на заполнитель значение, проходит молча. Обращайтесь со списком исключений как с контролем шума, никогда — как с гарантией, и никогда не помечайте настоящие учётные данные словами-заполнителями, чтобы заставить сканер молчать.
Проблема канонического фальшивого примера
Каждый поставщик публикует примеры учётных данных, и самый известный — пара документации AWS, построенная вокруг AKIAIOSFODNN7EXAMPLE, — имеет форму точь-в-точь как настоящий ключ, потому что пример, который не выглядел бы настоящим, ничему бы не научил. Сканеры затем оказываются перед развилкой без хорошего значения по умолчанию. Отмечать канонические примеры — и каждый учебник, пособие и учебный лог становится ложной тревогой, учащей читателей рефлекторно отбрасывать находки; усталость от тревог — сама по себе уязвимость. Вносить их в белый список — и вы опубликовали список строк, которые ни один сканер никогда не сообщит, приглашение для любого, кто ищет укрытие: настоящий ключ не может равняться примеру, но заметка, имя файла или обёртка вокруг настоящего ключа могут позаимствовать камуфляж примера.
Практический ответ — тот, который принимает редактор секретов: отмечать форму и давать таблице находок начать разговор. Канонический пример содержит слово example внутри самого ключа, но всё же отмечается как ключ AWS, потому что строка в форме поставщика заслуживает человеческого взгляда каждый раз — взгляд дёшев, а альтернатива — молчаливый пропуск для всего, что так же сформировано. Когда вы пишете документацию, помогайте и сканерам ваших читателей, и своему собственному: используйте очевидно синтетические значения, помечайте их словами-заполнителями в окружающем присваивании и никогда не вставляйте настоящий ключ в документ с правкой нескольких символов — частично отредактированный настоящий ключ всё ещё является утечкой учётных данных с лишними шагами, и сканеры тоже не могут отличить его от подлинного изделия.
Ротируйте, а не просто удаляйте — и делитесь безопасно
Если настоящий секрет уже был вставлен без редактирования, порядок операций имеет значение, а удаление идёт последним, если вообще идёт. Предположите, что значение было скопировано — индексом, уведомлением, скриншотом, цитатой коллеги, — и обращайтесь с ним как с публичным: сначала идите к поставщику и ротируйте учётные данные, отзывая старые, чтобы утечённая строка перестала работать, где бы она ни выжила. Только тогда удаляйте или редактируйте исходное сообщение, как гигиену, а не как исправление. Руководство OWASP по управлению секретами и проект gitleaks, оба перечисленные ниже, существуют для двух половин этого урока: управлять секретами так, чтобы они были короткоживущими и ограниченными по объёму, и сканировать репозитории и истории в предположении, что вставки уже произошли. Сопутствующая проблема для захватов браузера разбирается в перед тем, как отправить тот файл HAR.
Безопасный процесс обмена достаточно короток, чтобы стать привычкой. Во-первых, редактируйте локально, в инструменте, который никогда не загружает оригинал, — сканирование принадлежит вашему устройству, потому что отправка сырого текста удалённому редактору повторила бы утечку в самом акте её предотвращения. Во-вторых, делитесь отредактированной копией в тикете или чате, где она несёт всё, что нужно устранителю неисправностей, — конечные точки, время, формы ошибок, — кроме доступа. В-третьих, когда другой стороне действительно нужны сами учётные данные, отправляйте их через менеджер секретов или истекающую ссылку с одним просмотром, по каналу, отдельному от обсуждения, и скажите об этом в тикете, чтобы никто не вставил их обратно. Команды, принявшие эти три шага, перестают зависеть от бдительности — единственного контроля, который в конце концов всегда отказывает, — и начинают зависеть от рутины, а рутины — это то, что удерживает секреты вне тикетов при усталой пятничной вставке так же надёжно, как при осторожной в понедельник.