Вайб-кодинг против ИБэшника. Несмертельная битва. Часть 2
ХАБР / ИСТОРИЯ ОДНОГО ПРОЕКТА
Вайб-кодинг против ИБэшника. Несмертельная битва. Часть 2
Как специалист по безопасности получил доступ к панели администратора, почему старую версию пришлось остановить и как после этого мы заново построили защиту.
Продолжение истории о человеке, искусственном интеллекте и безопасности.

Коротко о первой части
Мы попросили ИИ написать систему защиты от утечек, много раз исправляли установку, сеть, блокировку сайтов, уведомления и внешний вид. Проект дошел до испытаний и выглядел почти готовым. Именно в этот момент специалист по безопасности решил проверить не красивую оболочку, а то, как программа отличает администратора от обычного пользователя.
Специалист по безопасности вступает в игру
К этому моменту приложение умело уже довольно много. Я позвал специалиста по информационной безопасности и попросил его не смотреть на красивую панель, а попробовать получить права администратора в обход наших правил. Он честно не посмотрел на красивую панель. Защитное поле, которое, как мне казалось, должен был создавать золотой логотип, почему-то не включилось.
Первый результат был неприятным:
Обычный пользователь может изменить доступный ему файл настроек и открыть панель администратора.
Запись о том, является ли компьютер обычным или администраторским, и список разрешенных администраторов хранились в двух простых файлах настроек. Пользователь мог изменить их, объявить свой компьютер администраторским или удалить адреса настоящих администраторов. Мы запретили обычному пользователю изменять папку программы, а запись о назначении компьютера перенесли в защищенные системные настройки. Без прав администратора менять ее нельзя. Нам казалось, что проблема решена.
Фраза «проблема решена» тогда звучала солидно. Теперь я слышу в ней примерно следующее — «ключ от сейфа лежит не под ковриком, а под другим ковриком».
Через некоторое выяснилось, что это еще не все:
Ключ удалось получить обычными встроенными командами системы. Затем папку программы скопировали на другой компьютер, где у проверяющего были полные права. После изменения записи о назначении компьютера и подстановки найденного ключа открылась панель администратора.
Проблема была не в командах, которыми воспользовался специалист. Неправильно была устроена сама система.
Ошибка оказалась простой, но серьезной. Один общий ключ одновременно шифровал сообщения и подтверждал право открыть панель администратора. Но программа сотрудника тоже должна знать этот ключ, иначе она не сможет читать служебные сообщения. Значит, ключ неизбежно находится на рабочем компьютере и однажды может попасть в чужие руки. Использовать его как удостоверение администратора было нельзя.
Если упростить, первая версия рассуждала так:
ПОЛУЧЕН ОБЩИЙ КЛЮЧ КОМПАНИИ
↓
ЧИТАЕМ РОЛЬ ИЗ ОБЫЧНОГО ФАЙЛА
↓
ЕСЛИ В ФАЙЛЕ НАПИСАНО «АДМИНИСТРАТОР» — ОТКРЫВАЕМ ПАНЕЛЬ
Именно в этой логике и была ошибка.
Ограничение прав на файлы и встроенная защита системы могут усложнить кражу ключа, но не исправляют ошибочную идею. Человек с полными правами на другом компьютере все равно может перенести туда папку программы, добраться до ключа и обойти эти ограничения.
Неприятное, но необходимое решение
В этот момент было два варианта.
Первый — продолжать латать старую версию: глубже прятать ключ, переименовывать файлы, добавлять новые проверки и шифровать настройки другим ключом, который все равно лежит внутри программы.
Второй — признать старую версию небезопасной и заново решить, как программа должна узнавать администратора и доверенный компьютер.
Мы выбрали второй путь. Старую установку перестали считать пригодной для работы. Это не означало отказ от самой идеи. Мы отказались от неудачной архитектуры системы.
Решение далось тяжело: эмоционально хотелось поставить еще одну заплатку, но на самом деле требовалось разобрать половину конструкции.
Самым полезным документом после этого стал простой список возможных атак. Мы заранее записали, что способен сделать обычный пользователь, что сможет человек с полными правами на компьютере и от каких действий наша программа вообще может защищать.
1. обычный пользователь может читать и изменять все, на что у него есть права;
2. он может завершать свои процессы;
3. он может копировать публичную часть приложения;
4. он может перехватывать сетевые сообщения и пытаться отправлять их повторно;
5. он может узнать общий ключ организации;
6. с полными правами, важные системные процессы, вредоносные системные модули и отключение антивируса находятся за пределами возможностей обычной программы.
После этого стало гораздо проще понять, что именно подтверждает каждый электронный ключ и каких прав он не должен давать.
Как мы заново построили защиту
Мы разделили программу на несколько частей. Обычный значок («рядом с часами») теперь только показывает состояние защиты. Он не хранит важные ключи и не принимает серьезных решений. Защищенные данные находятся в отдельной части программы, которая запускается самой операционной системой. Центральный сервер — отдельный главный компьютер — проверяет, каким устройствам разрешено работать. Право администратора подтверждается другими электронными ключами.
┌ КОМПЬЮТЕР СОТРУДНИКА ────────────────────┐
│ Значок на панелт показывает состояние,│
│ но не хранит важные ключи. │
└───────────────────┬─────────────────────────┘
│
┌───────────────────▼─────────────────────────┐
│ Защищенная часть программы │
│ хранит ключ компьютера, применяет правила, │
│ отправляет события и ставит обновления. │
└───────────────────┬─────────────────────────┘
│ зашифрованная связь
┌───────────────────▼─────────────────────────┐
│ Центральный сервер │
│ хранит список разрешенных, ожидающих │
│ проверки и заблокированных компьютеров. │
└───────────────────┬─────────────────────────┘
│
Подтвержденный администратор
У каждого компьютера появился собственный электронный ключ
При установке компьютер создает два связанных электронных ключа. Одну часть можно безопасно передать серверу, а вторая остается только внутри защищенной части программы. По ключу открытой части сервер присваивает компьютеру постоянный номер. Важен не способ вычисления, а сам принцип: у каждого компьютера свой ключ, и заменить его общим паролем компании нельзя.
ОТКРЫТАЯ ЧАСТЬ КЛЮЧА — ОТПРАВЛЯЕТСЯ НА СЕРВЕР
ЗАКРЫТАЯ ЧАСТЬ КЛЮЧА — ОСТАЕТСЯ НА КОМПЬЮТЕРЕ
ОБЕ ЧАСТИ ВМЕСТЕ — ПОДТВЕРЖДАЮТ, ЧТО ЭТО ТОТ САМЫЙ КОМПЬЮТЕР
Новый компьютер сначала попадает в список ожидающих проверки. Администратор может разрешить компьютер сотрудника, нового администратора подтверждает только главный администратор. Если компьютер потерян, взломан или попал в чужие руки, его можно заблокировать отдельно, не меняя настройки всех остальных устройств.
Почему одного подтверждения недостаточно
Чтобы изменить правила, установить обновление или открыть экран, недостаточно знать общий ключ компании. Каждая команда должна получить два независимых подтверждения. Первое подтверждает право администратора действовать от имени компании, второе — конкретный компьютер администратора, который заранее разрешен на центральном сервере.
В каждую команду добавляются точное время отправки и одноразовое случайное число. Получатель запоминает недавно выполненные команды и не принимает их второй раз. Поэтому злоумышленник не сможет перехватить правильную команду и повторить ее позже.
КАЖДАЯ КОМАНДА ПОЛУЧАЕТ:
— точное время отправки;
— уникальную одноразовую метку;
— подпись администратора.
Программа принимает такую команду только один раз.
Если просто скопировать папку программы на другой компьютер, у копии не окажется секретной части ключа исходного устройства. Центральный сервер увидит новый компьютер и снова отправит его на проверку. Общий ключ компании больше не дает права выполнять команды администратора.
Как сервер защищает сообщения
Центральный сервер хранит главный список разрешенных и заблокированных компьютеров. Связь с ним шифруется, а программа дополнительно проверяет специальное цифровое удостоверение своей компании. Оно помогает убедиться, что перед ней настоящий сервер, а не подмена. Если файл со списком компьютеров поврежден, сервер останавливается. Он не считает список пустым и не снимает защиту со всех устройств.
Каждое сообщение перед отправкой шифруется. Получатель также проверяет, что по дороге его никто не изменил. Старые незащищенные сообщения новая версия просто не принимает:
ПОЛУЧЕНО СООБЩЕНИЕ
↓
ПРОВЕРЯЕМ: ОНО ЗАШИФРОВАНО?
↓
ПРОВЕРЯЕМ: ЕГО НИКТО НЕ ИЗМЕНИЛ?
↓
ТОЛЬКО ПОСЛЕ ЭТОГО ЧИТАЕМ СОДЕРЖИМОЕ
Теперь общий ключ нужен только для защиты служебных сообщений и разделения разных компаний. Сам по себе он больше не дает прав администратора.
Просмотр экрана
Первая версия считала администратора доверенным только по адресу его компьютера в сети. Это ненадежно: адрес может измениться автоматически, а несколько компьютеров иногда выходят в сеть под одним общим адресом. Кроме того, злоумышленник может попытаться выдать свое соединение за доверенное.
Теперь перед показом экрана компьютер сотрудника и компьютер администратора сначала проверяют друг друга. Затем они создают отдельный секретный ключ только на время этого подключения: перед началом просмотра система проверяет администратора и компьютер сотрудника, затем создает защищенное соединение. Весь процесс состоит из следующих этапов:
1. создается одноразовый запрос, который нельзя использовать повторно;
2. проверяются право администратора действовать от имени компании и его разрешенный компьютер;
3. сервер подтверждает, что этот администратор не был заблокирован;
4. компьютер сотрудника тоже подтверждает свою подлинность;
5. сервер сверяет данные компьютера сотрудника со своей записью;
6. для текущего подключения создается временный секретный ключ;
7. обе стороны независимо получают один и тот же ключ связи, не передавая его по сети в готовом виде;
8. каждый кадр экрана отдельно шифруется и проверяется.
КОМПЬЮТЕРЫ ПРОВЕРЯЮТ ДРУГ ДРУГА
↓
СОЗДАЮТ ВРЕМЕННЫЙ ОБЩИЙ КЛЮЧ
↓
ОТДЕЛЬНО ШИФРУЮТ КАЖДЫЙ КАДР
↓
ПОСЛЕ ОТКЛЮЧЕНИЯ ВРЕМЕННЫЙ КЛЮЧ БОЛЬШЕ НЕ ИСПОЛЬЗУЕТСЯ
Даже если посторонний сможет подключиться к открытому сетевому входу программы, этого недостаточно для просмотра экрана. Во время проверки специалист по безопасности попробовал открыть экран с неподтвержденного компьютера администратора и получил отказ. Это был редкий случай, когда его тест закончился словами «не получилось».
Как мы защитили обновления
Раньше защищался только заголовок обновления, а сам файл передавался по сети без дополнительного шифрования. В новой версии архив делится на небольшие пронумерованные части, каждая весит около 32 кб. Каждая часть шифруется отдельно и связывается со всем обновлением.
АРХИВ ОБНОВЛЕНИЯ
↓
ДЕЛИМ НА НЕБОЛЬШИЕ ЧАСТИ
↓
НУМЕРУЕМ И ШИФРУЕМ КАЖДУЮ ЧАСТЬ
↓
ПОСЛЕ ЗАГРУЗКИ ПРОВЕРЯЕМ ОБНОВЛЕНИЕ ЦЕЛИКОМ
Если изменить в обновлении хотя бы одну часть, перепутать порядок частей или добавить файлы из пакета другой компании, программа отклонит обновление.
После получения файла она проверяет:
1. совпадает ли полученный файл с тем, который отправил администратор;
2. действительно ли обновление выпущено нами и не было изменено посторонним;
3. является ли новая версия более свежей, чем уже установленная;
4. предназначено ли обновление именно для этой компании — пакет другой организации программа не примет;
5. запускается ли установщик в специальном проверочном режиме. В этом режиме он ничего не устанавливает, но проверяет наличие всех необходимых файлов, правильность подписей и соответствие ключей компании.
Только после успешного завершения всех проверок программа сотрудника принимает обновление и передает его системной службе для фоновой установки. Старые версии программы не поддерживали новый защищенный способ получения обновлений, поэтому администратору необходимо один раз установить сотруднику новую базовую версию: запустить установщик для сотрудника непосредственно на его компьютере либо развернуть его централизованно средствами компании. После этого следующие обновления можно будет устанавливать удаленно.
Что мы стали проверять перед выпуском
К концу эксперимента стало понятно: одной проверки исходного кода программы недостаточно, нужно проверить установщики, архивы и права на файлы. Перед запуском пилотной версии мы:
1. сделали пятьдесят девять проверок, которые убеждаются, что новые исправления не сломали уже работающую защиту;
2. провели отдельную автоматическую проверку кода на опасные конструкции;
3. проверили используемые библиотеки на известные уязвимости отдельно для компьютера сотрудника, центрального сервера и программы администратора;
4. проанализировали подписанный перечень файлов для установщика и архива обновления;
5. убедились, что закрытый ключ администратора не попал в установщик сотрудника;
6. провели распаковку готовых установщиков и проверку их содержимого;
7. сделали быстрый пробный запуск шести готовых установщиков;
8. проверили доступность прав на файлах сервера: ключи может читать и изменять только их владелец, а остальные пользователи доступа не имеют;
9. проверили, что в готовом комплекте присутствуют все необходимые файлы и ни один из них не был изменен, заменен или утерян после сборки. Смысл простой: после подготовки программы составляется список того, что должно находиться внутри установочного комплекта. Перед выпуском система сверяет каждый файл с этим списком. Если хотя бы один файл пропал, изменился или был подменен, комплект не выпускается.
На последней проверке выяснилось, что папка с ключами сборки была зашифрована, но обычные пользователи все еще могли изменять саму папку. Прочитать ключи они не могли, зато могли удалить или заменить хранилище и сорвать выпуск программы. Мы отменили автоматически выданные права и оставили доступ только владельцу сборки, операционной системе и администраторам компьютера.
То есть последняя найденная проблема была не в сетевой криптографии, а в правах каталога на машине сборки. Очень в духе всего проекта: мы добрались до цифровых подписей, шифрования и защищенного обмена ключами, а в финале снова уперлись в обычные права доступа.
Что у ИИ получалось хорошо
После всего сказанного было бы нечестно сделать вывод, что ИИ здесь только мешал. Главное преимущество ИИ — скорость превращения сформулированного решения в работающий код. Он выполнял за часы объем механической работы, на которую у небольшой команды ушли бы недели. В итоге он рекордно быстро:
1. связал возможности операционной системы, защищенную часть программы, значок рядом с часами и панель управления в браузере;
2. создал центральный сервер и ограничил права его служебной части;
3. собрал обычные установщики, пакеты для массовой установки и обновления;
4. реализовал криптографические протоколы с помощью давно проверенных готовых средств; написал тесты на подмену данных, повтор старой команды, установку старой версии и замену адреса сервера;
5. поддерживал документацию и отдельные пакеты компаний.
Главное преимущество ИИ — скорость, с которой понятное решение превращается в работающую программу.
Где ИИ ошибался
Главный недостаток — он слишком долго и слишком уверенно решал не ту задачу. Когда я говорил «спрячь ключ», он прятал ключ. Когда говорил «не видит другую сеть», добавлял поиск компьютеров. Когда не работал установщик, появлялась новая копия установщика. Каждый отдельный ответ выглядел логично, но никто не остановился и не спросил: «А должен ли этот ключ вообще давать такие права?»
В итоге я увидел несколько повторяющихся проблем вайб-кодинга:
1. Уверенный код без зафиксированной модели угроз
ИИ может правильно применить надежный способ шифрования и одновременно построить всю выдачу прав на одном общем ключе, который хранится у пользователя. Шифрование будет работать правильно, но — вся защита окажется непригодной и дырявой.
2. Тесты подтверждают сформулированные ожидания
Если в проверке заранее записано «пользователь с общим ключом становится администратором», она успешно подтвердит именно это. Но она не объяснит, что само такое правило в крайней степени опасно.
3. Реальный компьютер сложнее испытаний на стенде
Русская версия операционной системы, антивирус, правила компании, разные сети, облачное хранилище, мессенджер, права на папки и временные файлы создавали сочетания, которых не было в лабораторных проверках.
4. ИИ любит плодить артефакты
Каждая пересборка создавала новую папку, архив, «final», «final2», временную распаковку и еще одну копию на флешке. В какой-то момент важной функцией проекта стала уборка собственных сборок. Мы ввели одно каноническое рабочее дерево и атомарную сборку пакетов.
До этого структура релизов напоминала семейное древо: у каждого final были дети, внуки и один загадочный архив, происхождение которого никто не хотел обсуждать.
Человек в этом проекте не писал код, но, по сути, руководил проектом и думал, как развивать проект, стоит ли латать дыры или перестраивать архитектуру. Человек нужен не для того, чтобы печатать код медленнее ИИ. Он нужен, чтобы вовремя спросить: «А мы вообще строим правильную систему?». Я не писал код, но приносил реальность: другой компьютер, другой антивирус, другую подсеть.
Можно ли теперь внедрять программу
Ответ зависит от того, что именно считать внедрением.
Для небольшого контролируемого пилота новая версия намного лучше первой. Общий ключ и редактирование файла роли больше не позволяют открыть панель администратора. Компании разделены, экран и обновления защищаются отдельно, а готовые сборки проходят автоматические проверки.
Для массовой установки в рабочей сети я пока не сказал бы «да». Остаются принципиальные ограничения:
1. у программы пока нет официальной цифровой подписи издателя, поэтому операционная система и антивирусы не могут сразу проверить, кто ее выпустил; внутренняя подпись обновлений этого не заменяет;
2. человек с полными правами на компьютере, часть самой операционной системы, вредоносная программа с такими же правами или отключенный антивирус остаются за пределами защиты обычного приложения;
3. определение передачи файла и его получателя по-прежнему строится на косвенных признаках и может быть ошибочным;
4. программа должна работать только внутри защищенной сети компании. Доступ к ней напрямую из интернета необходимо закрыть, попытки подключения – контролировать в обязательном порядке. Слишком частые запросы программа блокирует автоматически, но правильная настройка корпоративной сети все равно остается обязательной.
5. нужна независимая попытка взлома силами сторонних специалистов, а не только проверки автора, его товарища и автоматических программ;
6. нужно регулярно сохранять копию данных центрального сервера, а также заранее описать порядок замены ключей и блокировки компьютеров.
Полноценная система защиты от утечек — это не только программа на компьютере. Она также проверяет почту, распознает важные документы, собирает события безопасности, выполняет правила реагирования и постоянно приспосабливается к обновлениям операционной системы. Наш проект не мог внезапно заменить весь этот набор средств.
Но он стал рабочей площадкой для опытов и очень наглядным учебником.
А я теперь знаю два способа проверить зрелость программы безопасности: позвать ИБ-специалиста и запретить разработчику использовать слово final в имени файла. Второй способ дешевле, но первый все-таки полезнее.
Автор: MisterAzeri

