Поиск секретов в репозитории 1С-проекта: свой сканер, четыре сотни алертов, но ни одной реальной утечки
Разработка - Групповая разработка (Git, хранилище)
Файлы
ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.
Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний
Оформите подписку на компанию для решения рабочих задач
Оформить подписку и скачать решение со скидкойВы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
50.6-companion.zip: scan_repo.py, filter_long.py, jwt_fields.py, make_demo_repo.py, чек-лист разбора тревог, READMEДля 1С-команд, которые хранят выгрузку в Git: как устроен свой сканер секретов на регулярном выражении, что он нашёл в двух прогонах и как отделить настоящие ключи от названий полей и примеров. Прогоны 26.09 и 05.10.2026.
- Сканер читает только отслеживаемые файлы рабочей копии: история коммитов в область поиска не входит.
- Правило ловит форму строки: имя поля и разделитель,
eyJ…,bearer; смысл значения оно не знает. - Фильтр по длине, буквам и цифрам сократил 419 совпадений до 13 строк, все - контрольные строки и учебные JWT.
- Gitleaks нужен для истории Git; baseline сохраняется только после ручного разбора находок.
Тревоги сканера секретов почти всегда ложные, поэтому ценность даёт запись о том, что и где искали, и решение по каждой находке.
Для кого: 1С-разработчикам и тимлидам, которые хранят выгрузку конфигурации в Git.
- Предыстория
- Сканер читает рабочую копию, историю он не видит
- Правило смотрит на форму строки, смысл значения ему неизвестен
- Что делает обход файлов и где он ломается
- 42 совпадения, ноль секретов
- 419 строк читать незачем: хватило 13
- Gitleaks нужен там, куда мой обход не заходит
- Что здесь не проверено
- Источники
- Файл к статье
Кратко: сканер на одном регулярном выражении нашёл в моём репозитории 419 «секретов», настоящих среди них - ноль. Ниже (в статье) само выражение, обход файлов, оба прогона и фильтр, который избавил меня от чтения четырёх сотен тревог.
🛫 Предыстория
Свой сканер секретов я прогнала на одном репозитории дважды. В первый раз он нашёл сорок два совпадения, девять дней спустя - больше четырёхсот. Файлов за это время стало в пять раз больше, тревог - почти в десять. Первый прогон разобрал мой RPA Соавтор (мы не прячем, мы наоборот подчёркиваем роль AI в создании и написании таких сложных статей): прочитал каждое совпадение вместе с контекстом. Во втором я отобрала подозрительное фильтром. Итог одинаковый: ключей нет, есть названия полей, примеры кода и наши же контрольные строки для тестов.
Рядом с BSL и XML в проекте лежат инструкции, настройки автоматизации и результаты диагностических запусков, и секрет может прилипнуть к любому из них. Поэтому такую проверку стоит делать перед передачей кода и перед публикацией примеров. В конце - где нужен gitleaks и почему я пока не ставлю его вместо своего правила.
🧩 Сканер читает рабочую копию, историю он не видит
Список файлов сканер получает командой git ls-files и читает их с диска. К прошлым версиям он не обращается и по коммитам не ходит. Секрет, который убрали из текущего файла, но оставили в истории, такой обход не заметит.
Число 165 в первой строке вывода - длина списка имён от Git. Часть файлов скрипт потом пропускает, поэтому «проверено 165 текстовых файлов» было бы неправдой. Состояние копии записано в отчёте: отслеживаемые файлы до коммита главы 4, новые файлы самой проверки в выборку не вошли.
С новыми файлами то же самое. Создали файл с настройками и не добавили в индекс - в список Git он не попадёт, и сканер его не увидит. Поиск по рабочей копии и поиск по истории - разные задачи, вход у каждой надо записывать отдельно.
Поэтому каждый запуск я описываю короткой записью: состояние копии, откуда взят список файлов, какое правило. Без неё «совпадений нет» легко прочитать как «секретов нет нигде», хотя это относится только к тому, что сканер видел.
XML и BSL как язык сканер не разбирает. Расширения этих файлов не в списке исключений, поэтому они читаются как текст, если Git их знает и они лежат на диске. Похожие строки в них искать можно, отличить строковый литерал от комментария или имени реквизита нельзя.
Вывод прогона показывает, сколько шума даёт каждое правило. Отсутствие секретов во всём проекте он не доказывает.
🧰 Правило смотрит на форму строки, смысл значения ему неизвестен
В исходном сканере выражение импортируется из archive_door. Чтобы листинг запускался без этого модуля, привожу определение целиком, как в коде:
Первая ветвь ищет слово, похожее на имя поля, и разделитель : или =, затем забирает символы до ближайшего разделителя из списка. Имена на русском и английском расширяют поиск, но о пригодности значения для авторизации они ничего не говорят.
Перед именем поля нет границы слова, поэтому совпадение может начаться внутри длинного идентификатора. В списке результатов это видно: туда попали переменные и поля, у которых просто подходящий хвост. Каждую такую тревогу приходится разбирать отдельно.
Вторая ветвь ловит строку, которая начинается с eyJ и делится точками на три части. Третья - слово bearer и следующее за ним слово без пробелов. Это распознавание формы: подпись, назначение и срок действия значения код не проверяет.
В выводе остаются имя поля из группы key и *** вместо найденного, плюс до 12 знаков слева от совпадения; печатаемая строка обрезается. Место в файле найти можно, само значение целиком не печатается. Маска закрывает только найденную часть, а слева рядом может оказаться другое значение. Поэтому полный вывод я в статью не кладу даже с маской: здесь только счётчики и несколько обезличенных строк.
В проекте это же выражение уже стоит для маскирования текста перед выводом. В поиск я перенесла его как готовый набор подозрительных признаков. У маски и сканера разные задачи. Маска может закрыть лишнее без последствий, лишняя тревога сканера отнимает время на разбор.
Правило я оставила как есть. Подправь я выражение, старые 42 совпадения стало бы нельзя сравнивать с новыми: получился бы другой эксперимент.
📄 Что делает обход файлов и где он ломается
Основная часть scan_repo.py ниже целиком. До неё в исходнике определены корень проекта и импорт SECRET_RE. Для самостоятельного скрипта поставьте определение выражения из предыдущего раздела перед обходом и задайте ROOT под свой проект.
ROOT считается от положения скрипта. В нашем проекте скрипт лежит на три уровня ниже корня репозитория, отсюда parents[3]. Перенесёте файл на другой уровень - корень уедет, поэтому путь сначала напечатайте, потом запускайте обход.
Запускала так:
python scan_repo.py
Слабые места видны сразу. Код берёт только stdout и не смотрит на код завершения: если Git упал, список пуст, и вывод выглядит как «совпадений нет». Результат split() делит строку по любым пробелам, поэтому пути с пробелами могут развалиться на части. Такие имена на стенде я не проверяла и готовым универсальным обходом листинг не считаю.
Файлы читаются как UTF-8 с заменой ошибок декодирования. Обход не падает на другой кодировке, но заменённые символы могут исказить строку, так что полноту поиска для других кодировок я не обещаю. Исключены .png, .jpg, .pdf и .cfe, содержимое .cfe не разбирается. Остальные бинарные форматы скрипт не распознаёт, ограничения на размер файла нет. Перед проверкой выгрузки полезно знать, какие файлы текстовые, а каким нужен другой инструмент.
Для регулярной проверки я бы добавила контроль ошибок и список файлов и повторила прогон. Этой доработки в статье нет, поэтому сколько утечек она нашла бы, сказать не могу.
🧮 42 совпадения, ноль секретов
Первая строка сохранённого вывода:
файлов в git: 165, совпадений: 42, по видам: {'key=value': 38, 'bearer': 4}
Вид jwt в коде предусмотрен, но в этом прогоне совпадений по нему не было. Совпадения и файлы - разные счётчики: на одной строке и в одном файле их может быть несколько.
В тот раз мой RPA Соавтор разбирал совпадения по очереди, с контекстом, и записал в конце отчёта: «0 настоящих секретов». Я опираюсь на этот разбор как на готовую классификацию. Его и алгоритм сканера я прочитала; значения на действительность заново не проверяла.
Ложные срабатывания по содержанию: заголовки полей и пояснения, присваивания в коде, ссылка на секрет из workflow, слова об авторизации. Сканер видит буквы вокруг разделителя и один случай от другого не отличает.
| Содержимое места | Почему подходит правило | Что требует ручного разбора |
|---|---|---|
| Название поля с двоеточием и пояснением | Есть имя и разделитель | Проверить, является ли правая часть описанием |
| Присваивание переменной в примере кода | Есть подходящая часть имени и = |
Прочитать выражение справа |
| Обращение к хранилищу секретов workflow | Имя похоже на поле авторизации | Отличить ссылку от помещённого в файл значения |
| Текст о способе авторизации | Есть слово bearer и следующее слово |
Определить, является ли это термином |
Параметр key при сортировке |
Форма совпадает с первой ветвью | Проверить контекст вызова функции |
Последняя строка таблицы взята из списка результатов: там есть sorted(..., key= в Python. Из этого не следует, что любое key= безопасно. Одно и то же имя выглядит одинаково в разных местах, смотреть надо на выражение справа.
Часть совпадений пришлась на главу в Markdown и на её HTML-копию, так что один абзац даёт две тревоги. Посчитай я каждую отдельной утечкой, итог был бы завышен. При разборе полезно связывать копию с оригиналом, но помнить про оба места: в публикацию может попасть любое.
В JSON с текстовыми ответами одна физическая строка содержит длинное поле с экранированными переносами. Номер строки приводит к файлу, но смысл виден только после чтения самого поля: вложенный текст сканер построчно не разбирает.
Решения по тревогам стоит записывать: что проверили, почему признали примером или ссылкой, кто решил. «Обычно ложное срабатывание» разбором не считается. На том же месте при следующем изменении может появиться другое значение, и старое объяснение перестанет подходить.
Ручной просмотр относится только к совпадениям первого прогона. Сколько секретов сканер пропустил, из него не узнать: эталона утечек и проверки полноты в этих материалах нет. Если правило молчит, разбирать в отчёте нечего.
🔬 419 строк читать незачем: хватило 13
Второй прогон, 05.10.2026, Windows 11, Python 3.12.10, Git 2.56.0:
файлов в git: 823, совпадений: 419, по видам: {'key=value': 401, 'bearer': 15, 'jwt': 3}
Читать 419 строк подряд я не стала. Сначала разобрала три совпадения вида jwt и декодировала среднюю часть каждого. Одно оказалось известным учебным примером с полями "sub":"1234567890","name":"John Doe", два других - нашей контрольной строкой из теста утечек. Потом отобрала совпадения, где значение не короче 20 знаков, в нём есть и буквы, и цифры, и оно не похоже на вызов функции, путь или ссылку на переменную окружения:
Осталось 13 строк в пяти файлах: контрольные строки CANARY… из проверок маскирования и учебные JWT. Пороги подобраны под этот репозиторий, и пароль из восьми символов фильтр не заметит. Поэтому остальные совпадения я просмотрела по именам файлов: главы, их HTML-копии, выводы прогонов и код с key= в сортировке.
🚦 Gitleaks нужен там, куда мой обход не заходит
Gitleaks - готовый сканер с правилами для известных форматов ключей. По README, начиная с версии 8.19.0 команды detect и protect объявлены устаревшими (они ещё работают, но скрыты из --help), вместо них три режима: git, dir и stdin. Режим git сканирует патчи из git log -p, то есть историю коммитов, а мой обход по git ls-files до неё не добирается. Там же сказано, что gitleaks смотрит только добавленные в историю строки. README Gitleaks.
Baseline - любой ранее сохранённый отчёт gitleaks: находки из него при следующем запуске игнорируются, и в новом отчёте остаются только свежие. Отсюда порядок: сначала я разбираю все находки руками, потом сохраняю baseline. Если в него попадёт реальный ключ, следующий запуск спрячет его как уже известный.
Gitleaks на этой машине не установлен и на нашем репозитории не запускался, так что сравнить два инструмента на одной выборке я не могу. Для 1С-проекта я бы начала со своего правила и ручного разбора, как выше, а gitleaks добавила для истории Git: у него другая область поиска.
🧭 Что здесь не проверено
Первый прогон (26.09.2026) разобрал мой RPA Соавтор, каждую находку отдельно. Во втором (05.10.2026) я прочитала все совпадения вида jwt и строки, оставшиеся после фильтра, а остальные просмотрела по файлам, не по каждой строке.
Сканер читает отслеживаемые файлы рабочей копии. Историю Git, локальные неотслеживаемые файлы и содержимое .cfe он этим способом не проверяет. Эталона для измерения пропусков нет. Пути с пробелами и кодировки кроме UTF-8 не проверялись. Версии Git и Python первого запуска в отчёте не указаны.
Железо стенда (параметры сняты 08.10.2026): Intel Core i5-2400 3,1 ГГц (4 ядра, выпуск 2011 года), ОЗУ 7,9 ГБ, SSD Samsung 850 EVO 500 ГБ (SATA), Windows 11 Pro. Компьютер рабочий, во время прогонов параллельно шли браузер и другие программы. Время работы сканера в статье не приводится, поэтому на счётчики железо не влияет; на другой машине изменится только скорость обхода.
Gitleaks не запускался, его режимы и baseline описаны по README. Страница стандарта 1С «Безопасное хранение паролей» открылась, но тело требований прочитать не удалось: текст приходит в искажённой кодировке. Поэтому я не опираюсь на неё в утверждениях о шифровании и механизмах хранения. Хранение учётных данных и env.json разобраны в предыдущей публикации, здесь я их не пересказываю.
Значения из находок в статью не попали. Маска *** закрывает найденную часть, соседний контекст нужно смотреть отдельно. Ни «тревог нет», ни «тревоги ложные» не доказывают, что чисты все файлы и вся история проекта.
📚 Источники
- README Gitleaks - режимы
git,dir,stdin, baseline и предупреждение об устаревании командdetectиprotect. Читала веткуmaster, она может измениться; для запуска нужна документация установленной версии. - JWT Introduction - пример токена с полями
subиname, по которому я опознала учебный JWT. - Стандарт 1С «Безопасное хранение паролей» - смежная тема хранения; тело требований прочитать не удалось.
scan_repo.py,output.txtи определениеSECRET_REвarchive_door.py- алгоритм, сохранённые счётчики и ручной разбор. Код правила и обхода приведён в тексте.- Предшественники на Infostart: Где хранить учётные данные информационных баз 1С:Предприятия и что нельзя хранить в Git (env.json в 1С-проекте) (Ninel_S, 30.09.2026); Пароль СУБД из 1CV8Clst.lst достать нельзя? Можно. Проверьте свой кластер 1С (nedomolkov.ivan, 06.08.2026).
📎 Файл к статье
В архиве 50.6-companion.zip: сканер scan_repo.py с правилом SECRET_RE, фильтр длинных значений filter_long.py из раздела про 419 совпадений, jwt_fields.py для строк вида eyJ…, скрипт make_demo_repo.py, который создаёт учебный репозиторий для пробного запуска, чек-лист ручного разбора тревог, вывод прогона 06.10.2026 и README. Сначала проверьте корень репозитория и область поиска, затем разберите каждое совпадение в контексте. В чек-листе есть раздел для gitleaks: версия, прогон на стенде, разбор находок до baseline.
Коллеги, если станете комментировать, напишите, на каких строках сканер секретов срабатывал у вас чаще всего: на полях с именем key, на заголовках или на чём-то другом, и на какой выгрузке.
Вступайте в нашу телеграмм-группу Инфостарт
См. также
02.11.2026 415 vanya_gonchar 2