Вайб‑кодинг против ИБэшника. Несмертельная битва. Часть 1

Привет, Хабр! Меня зовут Артур, директор по безопасности NtechLab и энтузиаст вайб‑кодинга). Сегодня поговорим о применении вайб‑кодинга в информационной безопасности внутри компании: реально ли использовать нейросеть для создания продукта «под ключ» или это заранее путь в никуда. Присаживайтесь, нас ждет увлекательное путешествие и море слез — без этого никуда:)

Наша задача — создать внутреннюю систему защиты от утечек данных. Мы назвали ее Heimdall, да, в честь главного стража из скандинавской мифологии. Cистема должна показывать список включенных рабочих компьютеров, сообщать о подключении флешек и подозрительной отправке файлов, блокировать запрещенные сайты, устанавливать обновления в фоновом режиме и при необходимости давать администратору доступ к экрану сотрудника.

Идея создания «продукта под себя» родилась не из абстрактного желания поиграться с нейросетями, а ради формирования еще одного контура безопасности. Сотрудники уведомлены о применяемых средствах защиты, но мне хотелось не тотальной слежки, а понятной системы предотвращения и разбора инцидентов.

Первое «почти готово»

Для обычной команды разработки сделать полноценный продукт — работа на несколько этапов. Еще до написания кода пришлось бы отдельно описать, от кого мы защищаемся, какие данные считаем важными и какие действия разрешены каждой роли. В режиме вайб‑кодинга задача звучала гораздо проще: «там почти все готово, давай соберем». ИИ ответил ровно так, как умеет отвечать: уверенно и деятельно. Начались сборки.

Задача стояла создать продукт, который обеспечит:

  1. Отдельную установку для администратора и сотрудника;

  2. Автоматическое обнаружение компьютеров;

  3. Контроль USB и передачи файлов, внедрит политику запрещенных доменов;

  4. Уведомления администраторам, в том числе в Telegram;

  5. Фоновые обновления программы на компьютере сотрудника без его участия;

  6. Просмотр экрана при расследовании инцидента.

Весь код писал Codex.

Первые минут двадцать это ощущалось почти как управление очень быстрой командой разработки. Вначале казалось, что все почти готово. Потом волшебство закончилось и выяснилось, что у команды нет архитектора, тестировщика и чувства самосохранения, зато она может выпустить final_final_really_final.zip раньше, чем я успею допить чай.

Руководитель уверенно показывает почти готовую программу на фоне горы хаотичных сборок и уставшего разработчика.

Руководитель уверенно показывает почти готовую программу на фоне горы хаотичных сборок и уставшего разработчика.

Когда «там все почти готово» становится названием этапа разработки

Итак, первая версия была одной большой программой на Python. В ней одновременно находились: окно управления, значок в области уведомлений Windows, настройки, контроль сайтов и флешек, поиск компьютеров, обновления и показ экрана.

Упрощенно схема выглядела так:

┌ Компьютер сотрудника ─────────────────────┐
 │ Одна программа делает почти все: │
 │ показывает значок, читает настройки, │
 │ следит за сайтами и флешками, │
 │ принимает обновления и передает экран. │
 │ Роль и общий ключ лежат рядом в файлах. │
 └───────────────────┬─────────────────────────┘
 │ локальная сеть
 ▼
 ┌ Компьютер администратора ──────────────────┐
 │ Такая же программа, но с другой ролью. │
 └─────────────────────────────────────────────┘

Это действительно работало на столе разработчика. Оба процесса запускались, UDP‑пакеты летали, компьютер появлялся в списке. Проблема в том, что «появился в списке» и «получилась безопасная корпоративная система» находятся на разных планетах.

Мы долго жили в цикле:

новая функция → сборка → флешка → другой компьютер → ошибка
 ↑ │
 └──────────── срочное локальное исправление ┘

ИИ быстро исправлял отдельные ошибки. Не работает путь с пробелом — добавляли кавычки. Появились два процесса — запрещали второй запуск. Адрес сайта не совпадает с правилом — приводили адреса к одному виду. Но мы исправляли симптомы по одному и долго не пересматривали устройство системы целиком.

Это напоминало ремонт корабля на ходу, только корабль пока стоял на столе, а течь уже была в шести отсеках.

Установщик распадается на множество зависимостей и ошибок рядом с замершей полосой выполнения.

Установщик распадается на множество зависимостей и ошибок рядом с замершей полосой выполнения.

Установщик как отдельный жанр трагикомедии

Первый установщик состоял из командных файлов Windows и сценариев PowerShell. На моем компьютере он иногда работал, а на другом мог показать набор непонятных команд и остановиться.

'БКА]' is not recognized as an internal or external command
 '«tracked_domains»:' is not recognized as an internal or external command
 The system cannot find the path specified

Причины были вполне обычными: разные кодировки, служебная отметка в начале текстового файла, кириллица, кавычки и попытка записать настройки прямо из командной строки. Но для пользователя результат выглядел одинаково: установка не работает.

В какой‑то момент установщик начал разговаривать на языке, которого не знали ни я, ни Windows. Судя по набору символов, он знал о проекте что‑то страшное, но отказался переводить. Вот только некоторые из ошибок, с которыми мы столкнулись:

  1. Файл назначения уже занят запущенным процессом;

  2. Установка запускается с правами администратора, поэтому на компьютере сотрудника по ошибке открывается панель администратора;

  3. Права на C:ProgramDataHeimdall‑Guard применяются через локализованные имена групп и ломаются на русской Windows;

  4. Антивирус удаляет установщик, потому что его действия похожи на поведение вредоносной программы;

  5. Сборщик PyInstaller упаковывает программу в один файл, но при запуске временно распаковывает ее. Обновление или антивирус успевает удалить нужную библиотеку, и программа больше не запускается;

  6. Удаленное обновление передает не тот исполняемый файл или не находит его после распаковки.

Особенно неприятной была ошибка:

Failed to load Python DLL
 C:ProgramData_MEI...python314.dll
 LoadLibrary: Не найден указанный модуль

Она возникала именно там, где от агента требуется незаметное фоновое обновление. Пользователь получал окно ошибки от средства, которое должно было работать без его участия.

В итоге установка эволюционировала в три формы:

  1. Отдельный установщик для администратора и отдельный установщик для компьютера сотрудника;

  2. Обновление в виде обычной папки с файлами, чтобы программа не распаковывалась каждый раз во временный каталог;

  3. Стандартный установочный пакет MSI, который можно незаметно развернуть на компьютеры через групповую политику Windows.

Обычный установщик Windows ставит программу сотрудника от имени системы, останавливает предыдущую версию, не позволяет случайно заменить новую версию старой и подробно записывает весь процесс установки. Это намного скучнее самодельного сценария PowerShell — и именно поэтому надёжнее.

Вообще, один из главных признаков взросления этого проекта состоял в том, что слово «скучно» постепенно перестало быть критикой и стало комплиментом.

Пилотный пользователь: должность не указана, обязанности бесконечны

У проекта был еще один участник, которого не было ни на одной схеме: сотрудник с пилотным компьютером. В документации его компьютер назывался просто «компьютером сотрудника». На деле сам сотрудник стал испытательным стендом и человеком, которому несколько раз в день говорили: «мы тут совсем чуть‑чуть поправили» и — любимое — «почти все готово».

К этому моменту слово «почти» уже стало у нас единицей измерения. Один «почти готовый» релиз равнялся примерно трем новым установщикам, двум ночным перепискам и одному человеку, который спрашивал, почему у него опять ничего не видно.

Уставший сотрудник пытается работать, пока коллеги снова предлагают установщик, флешку и перезагрузку.

Уставший сотрудник пытается работать, пока коллеги снова предлагают установщик, флешку и перезагрузку.

Сотрудник‑испытательный стенд

Для меня новая сборка означала еще один шаг к продукту. Для него — остановить нормальную работу, закрыть приложения, удалить старую версию, поставить новую, перезагрузиться, вставить флешку, открыть запрещенный сайт, дождаться уведомления и наконец попытаться вернуться к документу, который он собирался закончить еще утром.

— Установил?
— Установил.
— Перезагрузил?
— Да.
— Отлично. Я уже собрал новую версию.

Иногда после переустановки исчезал значок в области уведомлений Windows. Иногда первой открывалась панель администратора. Иногда запускались два процесса, но ни один не делал нужную работу. Иногда программа не находила собственную библиотеку. Рабочий компьютер по очереди становился компьютером сотрудника, компьютером администратора и загадочным устройством с двумя процессами и — без единой иконки.

«Тестировщик поневоле» ругался. Не всегда литературно, зато почти всегда по существу. За экспрессивной формой скрывались отличные баг‑репорты: «после обновления все слетело», «флешку вставил — тишина», «сайт открывается», «экран погас». В какой‑то момент его раздражение оказалось точнее любой системы мониторинга. Самое неприятное состояло не в том, что тесты падали. Мы действительно мешали человеку работать.

Этот эпизод хорошо отрезвил. Пользователь пилота — не бесплатная тестовая инфраструктура и не человек, обязанный радоваться нашей скорости. Его рабочее время тоже входит в стоимость разработки. Просто в первых версиях сметы мы почему‑то забыли эту строку.

Позже мы ввели правила, которые стоило установить с первого дня: одно согласованное окно тестирования, одна утвержденная сборка, журнал изменений, понятный откат и сбор диагностики до очередной переустановки.

Одна Wi‑Fi‑сеть, которая оказалась несколькими и домен, которого нет

Следующая проблема была связана с сетью. Два компьютера могли быть подключены к одному Wi‑Fi, но находиться в разных частях корпоративной сети. Широковещательный запрос, которым программа искала соседние компьютеры, через маршрутизатор не проходил. Поэтому «один Wi‑Fi» еще не означает, что компьютеры могут напрямую найти друг друга.

Сначала программа пыталась сама изучать доступные сети, проверять диапазоны адресов и рассылать запросы. Но это работает только там, где сетевые правила уже разрешают связь. Программа не может сама отменить запреты, установленные маршрутизатором или межсетевым экраном.

Для пользователя оба компьютера были «в одном вайфае». Для маршрутизатора это были две суверенные державы с визовым режимом и закрытой границей.

Два сотрудника находятся под одним значком Wi-Fi, но их компьютеры разделяет укрепленная стена межсетевого экрана.

Два сотрудника находятся под одним значком Wi‑Fi, но их компьютеры разделяет укрепленная стена межсетевого экрана.

Один Wi‑Fi. Две подсети. Международные переговоры не предусмотрены.

Тогда появился центральный сервер на Ubuntu. Агент на компьютере сотрудника сам подключается к нему, а программа администратора получает через тот же сервер список компьютеров и событий.

Компьютер сотрудника ──► Центральный сервер ◄── Компьютер администратора
 сам подключается хранит список получает события компьютеров

Для просмотра экрана и установки обновления программа администратора подключается к компьютеру сотрудника по отдельному защищенному каналу.

Центральный сервер помог компьютерам находить друг друга через разные сети. Но появились новые вопросы: кто может к нему подключаться, как отделить одну компанию от другой, как проверить подлинность сервера и как не превратить открытый сетевой порт во вход для постороннего.

Когда инфраструктурный администратор получил первый Ubuntu‑архив, выяснилось, что «сборка существует» и «ее может установить другой человек» — разные состояния продукта.

В одном месте инструкция требовала файл install.sh, в другом предлагала запустить build_unix.sh, а нужного файла внутри архива вообще не было. Названия файлов с ключами уже изменились, но документ продолжал ссылаться на старые. Центральный сервер и программу администратора для Ubuntu мы описали так похоже, что человек не понимал, что именно он установил.

Получился квест: найди файл, которого нет, выполни команду из другой главы и догадайся, какой из двух одинаково названных компонентов ты только что установил. Призов за прохождение не предусматривалось.

Для меня это был болезненный, но полезный момент. В итоге архив разделили:

  1. Центральный сервер на Ubuntu — принимает подключения компьютеров и хранит их состояние; программа администратора — показывает панель управления только на компьютере администратора;

  2. Для Windows используются разные установщики: один для администратора, другой для сотрудника;

  3. Защищённый файл с настройками организации разворачивается скриптом автоматически;

  4. В инструкции появился порядок: сначала центральный сервер, затем главный администратор, потом остальные администраторы и только после этого компьютеры сотрудников;

  5. Полноценную документацию сделали в PDF, начали рендерить постранично и проверять визуально, а не считать готовой потому, что Библиотека для создания PDF завершила работу без ошибок.

Документация перестала быть приложением к коду. Она стала частью релиза и его тестирования. Это открытие стоило нам нескольких архивов, одного раздраженного администратора и окончательного запрета на фразу «там все интуитивно понятно».

Передача файлов

Самым показательным стал OneDrive. Сотрудник просто открывает рандомный PDF или документ, Windows активирует синхронизацию, и прототип пишет «передача файла». Потом сотрудник реально отправляет файл через Telegram, а события нет.

Обычная программа Windows видит только косвенные признаки: какой процесс открыл файл и устанавливал ли он после этого сетевое соединение. Без глубокой интеграции с мессенджером, почтой или сетевым шлюзом она не может надежно сказать, кому именно отправили файл.

Прототип в этот момент напоминал слишком тревожного охранника: на шорох OneDrive поднимал тревогу, а реального посетителя с коробкой документов вежливо пропускал.

Охранник поднимает тревогу из-за безобидного облака с PDF, не замечая человека, выносящего коробку документов.

Охранник поднимает тревогу из‑за безобидного облака с PDF, не замечая человека, выносящего коробку документов.

Поэтому теперь интерфейс честно говорит: это не доказанный факт передачи, а предположение по косвенным признакам. Для презентации звучит скромнее, зато пользователь понимает, насколько можно доверять событию.

Достаточно быстро удалось разрешить проблему с удаленным экраном. С одной стороны, такая опция появилась быстро и просто, с другой — программа ошибочно считала каждый новый кадр отдельным событием. Кадры обновлялись несколько раз в секунду, и Telegram вместе с областью уведомлений Windows сообщали о каждом из них очень добросовестно — телефон за несколько секунд превращался в персональный прибор для измерения частоты кадров. Исправление оказалось простым: сообщать только о начале и окончании просмотра экрана, а промежуточные кадры вообще не считать отдельными событиями.

Телефон и рабочий стол завалены лавиной одинаковых уведомлений от трансляции экрана.

Телефон и рабочий стол завалены лавиной одинаковых уведомлений от трансляции экрана.

Одно подключение к экрану. Тысяча очень важных уведомлений.

Как красивый интерфейс сделал прототип похожим на продукт

Сначала панель администратора была большим окном на Tkinter. Функций становилось больше, вкладки разрастались, а нужную информацию было все труднее находить. Поэтому я попросил полностью переделать интерфейс.

Так появилась веб‑панель, которая открывается только на компьютере администратора. В ней были список компьютеров, происшествия, правила, обновления и отдельный экран для событий высокого риска. Карточку риска сделали кликабельной, чтобы сразу было видно, почему система считает событие опасным.

 ┌──────────────┬─────────────────────────────────────────────┐
 │ Мой_ДЛП │ В сети │ Высокий риск │ Обновления │ Сервер │
 │ Guard ├─────────────────────────────────────────────┤
 │ │ События │
 │ Обзор │ [82] КОМПЬЮТЕР-01 флешка и копирование │
 │ Компьютеры │ [45] КОМПЬЮТЕР-02 запрещенный сайт │
 │ События │ │
 │ Правила │ Почему риск высокий │
 │ Обновления │ • критическое событие │
 │ Журнал │ • повтор за последние 15 минут │
 └──────────────┴─────────────────────────────────────────────┘

Веб‑панель намеренно доступна только на том компьютере, где установлена программа администратора.

def run_server(host=“0.0.0.1.”, port=0000):
 if host not in (“0.0.0.1”, “::1”, “localhost”):
 raise ValueError(“console may only bind to loopback”)
 
 if current_role() not in (“Admin”,
 raise PermissionError(“administrator credential is missing”)

Кроме адреса программа проверяет, откуда пришел запрос, и требует случайный секретный код текущего запуска. На Ubuntu используется тот же подход: панель не выставляется в общую сеть, а администратор открывает ее через защищенное SSH‑соединение.

Красивый интерфейс сильно изменил восприятие проекта. И это было опасно. Когда система выглядит цельной, ей начинают приписывать цельность внутри. Даже мы сами, разработчики, повелись на эту небольшую маркетинговую уловку — красиво = хорошо работает.

Черный фон и золотой логотип обладают удивительным свойством: рядом с ними даже ошибка сервера с номером 500 выглядит как дорогая корпоративная функция. Эта ошибка нам стоила крайне дорого и откатило сборку назад на несколько шагов — расскажем во второй части.

Автор: MisterAzeri

Источник

Оставить комментарий