HTTP или SSH для AI-агентов: ограничиваем радиус поражения
Как выбрать HTTP или SSH для AI-агентов: сравниваем полномочия, аудит, безопасность повторов и сбои, из-за которых маленькая задача получает широкий доступ.

AI-агенту стоит использовать HTTP, когда сервис может представить нужное действие как узкую аутентифицированную операцию. SSH нужен только тогда, когда задаче требуется возможность на уровне машины, которой нет у API. И даже в этом случае подключение должно идти через учётную запись и набор команд, созданные специально для этой задачи.
Обычно эти два транспорта сравнивают так, будто один современный, а другой устаревший. Такой подход уводит от сути. HTTP и SSH лишь доставляют запрос. Всё решают полномочия, которые вы им даёте, принимаемые входные данные и сохраняемые доказательства. От этого зависит, внесёт ли агент ограниченное изменение или начнёт ходить по рабочему хосту с правами администратора.
Я видел, как команды выдавали якобы временный SSH-ключ, потому что агенту требовался один рабочий факт. Через месяц этот ключ уже позволял читать секреты развёртывания, обращаться к внутренним сервисам и запускать интерактивную оболочку. Никто не принимал какого-то драматичного решения по безопасности. Все просто согласились на удобную настройку по умолчанию. Именно так маленькая задача получает большой радиус поражения.
Интерфейс определяет полномочия агента
Вопрос «HTTP или SSH для AI-агентов» связан с формой возможностей, а не с предпочтением протокола. HTTP-вызов может быть широким и опасным, а SSH-подключение, наоборот, строго ограниченным. На практике API чаще дают удобную точку для ограничения полномочий: конечная точка, метод, схема запроса и разрешение токена вместе могут описывать одну операцию.
Представим инструкцию: перезапустить неисправный процесс. Конечная точка HTTP вроде POST /workers/worker-17/restart указывает и цель, и разрешённое действие. Сервис может отклонить неизвестный процесс, потребовать роль с правом перезапуска и записать событие, связанное с токеном. Команда оболочки вроде ssh host sudo systemctl restart worker подразумевает гораздо более широкие полномочия. Она зависит от учётной записи, настроек sudo, правил именования служб, разбора оболочки и состояния хоста.
Это не значит, что API автоматически безопасен. Токен, который может вызывать все конечные точки, создавать другие токены или экспортировать все записи, имеет большой радиус поражения, даже если за ним стоит аккуратный URL. И наоборот, принудительная SSH-команда, принимающая фиксированный идентификатор процесса из списка разрешённых значений, может быть безопаснее плохо спроектированного административного API.
Перед подключением любого инструмента проведите простой тест: запишите минимальное успешное действие одним предложением, а затем перечислите, что ещё сможет сделать та же учётная запись, если агент передаст неожиданные данные. Если вы не можете объяснить вторую часть, полномочия ещё не измерены.
Узкий интерфейс обладает четырьмя свойствами:
- Он называет небольшой набор целей, а не всю среду.
- Он принимает структурированные данные с грамматикой, которую можно проверить.
- Он отклоняет соседние действия, не нужные для текущей задачи.
- Он создаёт запись, по которой другой человек позже сможет объяснить результат.
Задача должна определять и срок жизни учётных данных. Ключ или токен для одного запуска не должен незаметно превратиться в постоянный доступ только потому, что его забыли удалить. Граница по времени жизни процесса надёжнее напоминания в календаре.
HTTP даёт полезные границы только при проверке на стороне API
HTTP уменьшает радиус поражения агента, когда сервис проверяет права на уровне ресурса и операции. Bearer-токен лишь переносит данные для доступа. Безопасность определяется тем, что сервер проверяет после получения токена.
RFC 9110 описывает методы HTTP через их семантику, включая различие между безопасными и идемпотентными методами. Это помогает разобраться с повторами и намерением запроса, но не даёт разрешений. GET может раскрывать конфиденциальные данные. PUT может быть идемпотентным, но при этом перезаписывать рабочую настройку. Считайте названия методов подсказками для поведения клиента, а не моделью разрешений.
До передачи токена задайте владельцу сервиса такие вопросы:
- Какие именно пути и методы может вызывать этот токен?
- Проверяет ли сервис доступ к каждому ресурсу или только к общей коллекции?
- Может ли токен создавать учётные данные, менять разрешения или запускать экспорт?
- Может ли идентификатор вывести запрос в другой арендатор, проект или среду?
- Записывает ли сервис идентификатор учётных данных и результат запроса?
Неприятный вопрос звучит так: не раскрывает ли разрешение на чтение больше, чем нужно задаче? API репозитория может позволить токену чтения получать исходный код, комментарии к запросам на слияние, логи сборок и конфигурацию. Одно неудачно сохранённое значение конфигурации способно превратить доступ на чтение в доступ к секретам. Если агенту нужно только состояние одного развёртывания, выдайте ему конечную точку, которая возвращает именно это состояние. Не передавайте общий токен репозитория и не называйте это минимальными полномочиями.
Схема запроса важна не меньше области действия. Сравним два запроса:
POST /v1/releases/release-42/promote HTTP/1.1
Authorization: Bearer token-value
Content-Type: application/json
{"environment":"staging"}
POST /v1/admin/execute HTTP/1.1
Authorization: Bearer token-value
Content-Type: application/json
{"operation":"promote","arguments":{"environment":"staging"}}
Оба запроса могут продвигать релиз. В первом серверу почти нечего интерпретировать. Второй создаёт административный диспетчер. В таких диспетчерах сначала появляются исключения, затем произвольные названия операций, а потом токен, реальные полномочия которого трудно описать. Я избегаю их для агентских задач, если только сервер не применяет строгий список разрешённых операций и отдельно не проверяет схему аргументов каждой операции.
Если сервис это позволяет, используйте разные учётные данные для разных действий. Разделяйте наблюдение и изменения, а обычные изменения и операции с учётными записями или оплатой. Настройка займёт больше времени, зато ошибки авторизации станут понятными. Отказ показывает, что описание задачи и учётные данные не совпадают. Широкий токен превращает каждую ошибку в успешно выполненный запрос, который приходится расследовать постфактум.
Не помещайте долгоживущий секрет API в запрос агента, файл окружения, настройку репозитория или конфигурацию инструмента. Проблема не ограничивается случайной утечкой в выводе. Агенты изучают окружение, инструменты собирают диагностику, а процесс с доступом к текстовому секрету может передать его в другое место. Храните секрет за пределами процесса агента и авторизуйте результат действия вместо передачи самого секрета.
SSH раскрывает хост, если намеренно не убрать оболочку
SSH по умолчанию имеет большой радиус поражения, потому что интерактивная учётная запись может просматривать файлы, запускать программы, менять конфигурацию, открывать туннели и использовать все доступные ей сетевые пути. Намерение выполнить одну команду не ограничивает учётную запись, которой выдали обычную оболочку.
RFC 4251 описывает SSH как протокол для безопасного удалённого входа и других защищённых сетевых служб. Он специально поддерживает сессии, каналы, перенаправление портов и несколько методов аутентификации. Для администраторов это полезные возможности. Для автономного исполнителя, которому нужна одна ограниченная операция обслуживания, это плохая отправная точка.
Важна и сама команда. systemctl restart service-name кажется ограниченной, пока не проверить окружающие полномочия: какие службы может перезапускать учётная запись, могут ли файлы служб запускать привилегированные действия, может ли учётная запись менять эти файлы и проходят ли имена служб проверку. Операционная на вид команда может получить доступ к учётным данным развёртывания, подключённым томам или внутренней системе управления через службу, которую она перезапускает.
Если SSH необходим, создайте небольшую удалённую программу с закрытой грамматикой ввода. Она должна сопоставлять известные поля запроса с известными операциями. Нельзя просто склеивать запрос в команду оболочки. Не принимайте пути к файлам, имена хостов, регулярные выражения, фрагменты оболочки или назначения окружения, если программа не проверяет каждое значение по строгому списку разрешённых вариантов.
Ограниченная запись в authorized_keys помогает явно обозначить эту границу. Следующий шаблон принудительно запускает одну программу-получатель и отключает несколько функций SSH, которые агентам обычно не нужны:
command="/usr/local/libexec/agent-maintenance",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIexample agent-runner
Эта строка сама по себе не решает задачу авторизации. Программа agent-maintenance должна отклонять неизвестные подкоманды и проверять аргументы. У операционной учётной записи должны быть только права на файлы, службы и сеть, которые нужны этой программе. Если программа вызывает sudo, правило sudo должно называть фиксированный исполняемый файл и не разрешать редактор, интерпретатор, подстановочные символы или выход в оболочку.
Руководство OpenSSH по authorized_keys описывает command=, no-pty и ограничения перенаправления. Считайте эти параметры ремнём безопасности, а не автомобилем. Они убирают несколько простых путей обхода, но принудительная команда с правами слишком привилегированной учётной записи всё равно получает слишком много доступа.
Полезный протокол удалённого ввода может быть простым JSON в стандартном вводе:
{"action":"restart_worker","worker":"worker-17","request_id":"8b4f3c2a"}
Получатель должен принимать только restart_worker и имена процессов из собственного списка. До выполнения он должен записать событие, вызвать фиксированную программу без оболочки, сохранить код завершения и записать событие о завершении. Если агент отправит worker-17; cat /etc/shadow, проверка должна отклонить всё значение до запуска любой команды операционной системы.
Не выдавайте агенту SSH-доступ только потому, что человек выполняет ту же работу через SSH. Человек может заметить необычное приглашение, проверить несоответствие имени хоста и остановиться после неожиданного результата. Агенту нужны ограничения, встроенные в интерфейс.
Журнал должен объяснять и попытку, и полученное состояние
Строка журнала «запрос не выполнен» не является записью аудита. Для отладки клиентской библиотеки её может хватить, но она не ответит, изменил ли агент что-то, одобрил ли это человек и что проверять после инцидента.
Для HTTP сохраняйте идентификатор запуска агента, идентификатор или метку учётных данных, хост назначения, метод, нормализованный путь, безопасное представление тела запроса, статус ответа, значение для корреляции, время начала и итог. До выхода события за границу действия удаляйте секреты и чувствительные поля. Запись заголовка Authorization ради сохранения доказательств сама создаёт утечку.
Для SSH записывайте идентификатор хоста, удалённую учётную запись, название принудительной команды, проверенные аргументы, идентификатор исходного процесса, код завершения, классификацию стандартного вывода ошибок и идентификатор удалённой операции. Одна необработанная строка команды служит слабым доказательством: она может скрывать особенности кавычек и не показывает, какие аргументы принял получатель.
Последовательность событий должна отделять намерение от результата. Такая форма подходит обоим транспортам:
{"event":"authorization_granted","run":"r-204","action":"restart_worker","target":"worker-17"}
{"event":"action_started","run":"r-204","transport":"ssh","operation":"restart_worker","request_id":"8b4f3c2a"}
{"event":"action_finished","run":"r-204","outcome":"success","remote_status":0,"request_id":"8b4f3c2a"}
Если соединение оборвалось после action_started, записывайте outcome:"unknown", а не выдумывайте ошибку. Это заставляет правильно действовать дальше: сначала запросить удалённое состояние и только потом решать, нужен ли повтор. Такая запись также делает последующее расследование честным.
У обычных логов есть ещё и проблема сохранности. Администратор хоста или процесс с достаточными правами может обрезать, переписать или удалить их. Централизованный сбор помогает, но разрывы всё равно возможны при сбое коллектора или сети. Если журнал должен разрешать споры о действиях агента, храните записи только с добавлением, проверяйте их целостность и проводите проверку вне пути выполнения действия.
Цепочка хешей позволяет обнаружить изменения: каждое событие включает дайджест предыдущего. Она не доказывает, что регистратор увидел все события, и не делает ненадёжные часы надёжными. Эти ограничения важны. Цепочка отвечает на более узкий, но полезный вопрос: изменил ли кто-то сохранённую последовательность постфактум?
Sallyport хранит журнал Sessions для запусков агентов и журнал Activity для отдельных вызовов. Оба журнала формируются из зашифрованного аудита с цепочкой хешей. Команда sp audit verify проверяет эту цепочку офлайн поверх шифротекста. Это полезно, когда нужно изучить доказательства, не раскрывая сначала секреты.
Тайм-ауты создают неизвестный результат, а не неудачное действие
Именно сетевые сбои заставляют даже осторожные команды выполнять изменения дважды. Клиент отправляет запрос, удалённая сторона выполняет работу, а ответ теряется. Агент видит тайм-аут и запускает действие снова. С SSH то же самое может произойти после старта удалённой команды, но до получения клиентом её кода завершения.
Не позволяйте агенту воспринимать транспортную ошибку как разрешение повторить изменение. Сначала определите тип операции.
Операция идемпотентна только тогда, когда повтор того же запроса приводит к тому же нужному состоянию без дополнительного эффекта. Установка желаемого состояния конкретного процесса в running может соответствовать этому определению. Создание платежа, добавление записи, смена секрета или перезапуск процесса часто не соответствуют. Перезапуск может прервать восстановление, которое уже начал первый запрос.
Используйте идентификатор идемпотентности, если API его поддерживает. Сервис должен сохранить идентификатор вместе с выполненным действием и вернуть прежний результат при повторе. Идентификатор запроса, который сервер лишь записывает в журнал, не предотвращает дублирование.
Для удалённых команд добавьте операцию состояния, способную ответить на точный вопрос. После неудачного ответа restart_worker запросите текущее поколение процесса, идентификатор последнего запроса на перезапуск и состояние здоровья. Если получатель сохраняет идентификатор до запуска и возвращает его при запросе состояния, агент после повтора сможет понять, выполнялся ли запрос раньше.
Эта последовательность показывает, почему это важно:
- Агент отправляет запрос на перезапуск
worker-17с идентификатором8b4f3c2a. - Получатель сохраняет идентификатор и перезапускает процесс.
- SSH-соединение обрывается, пока процесс останавливается.
- Агент запрашивает состояние, а не запускает перезапуск снова.
- Ответ показывает, что тот же идентификатор ещё выполняется, поэтому агент ждёт и проверяет состояние здоровья.
Лимит повторов не устраняет неоднозначный результат. Он лишь ограничивает ущерб после неправильного решения. Наблюдение за состоянием исправляет само решение.
У HTTP есть ещё одна опасность: сервис иногда возвращает успешный статус до завершения асинхронной работы. 202 Accepted означает, что сервер принял работу для последующей обработки, а не что нужное состояние уже существует. Требуйте ресурс операции или конечную точку состояния и заставляйте агент ждать важного для задачи окончательного результата.
У SSH есть аналогичная ловушка, когда команда запускает фоновую работу и завершается с кодом 0. Нулевой код запускающего процесса не доказывает, что обслуживание завершено. Получатель должен дождаться завершения или вернуть постоянный идентификатор операции, который агент сможет запросить.
Команда оболочки скрывает больше полномочий, чем видно по тексту
Короткая удалённая команда часто обладает самыми широкими скрытыми полномочиями. На результат влияют расширение оболочки, наследование окружения, текущий каталог, файлы конфигурации и пути поиска исполняемых файлов. Агент может создать безобидный на вид текст, который даст неожиданный результат из-за контекста хоста.
Избегайте такого шаблона:
ssh ops@host "deploy $branch $environment"
Даже если сегодня вызывающая сторона правильно экранирует переменные, удалённая оболочка разбирает язык команд. Скрипт развёртывания может выполнять собственные подстановки. Имя ветки может выбрать источник. Имя среды может выбрать учётные данные или целевой кластер. Прежде чем утверждать, что ввод ограничен, нужно проверить каждый уровень.
Используйте получателя, который читает структурированные данные и напрямую вызывает фиксированный исполняемый файл. В большинстве языков это означает массив аргументов, а не строку, переданную в sh -c. Получатель должен сам сопоставлять понятное пользователю имя цели с идентификатором конкретного хоста. Не заставляйте агента самостоятельно находить пути в файловой системе или имена служб.
То же относится к параметрам HTTP. Путь вроде /files?path=... может выглядеть структурированным, пока сервер не передаст это значение файловой операции. API снижает риск только тогда, когда сервер проверяет смысл данных, а не просто переносит разбор команд за URL.
Размещение учётных данных меняет последствия компрометации процесса агента. Если агент хранит локально закрытый SSH-ключ или токен API, любой процесс с доступом к этим данным сможет действовать позже без агента. Отдельная граница действий может хранить секрет и передавать удалённому сервису только запрос вместе с решением об авторизации. Разница принципиальна: скрыть секрет от вывода модели не значит убрать его из процесса агента.
Sallyport использует такой подход для HTTP-учётных данных и SSH-ключей: приложение хранит их в зашифрованном хранилище и выполняет запрошенное действие, не передавая материал ключа агенту. Это не делает опасный запрос безопасным, поэтому цели всё равно нужно ограничивать, а подтверждения проверять.
Выбирайте транспорт на основе письменного сравнения возможностей
Обоснованный выбор не требует долгого семинара по рискам. Запишите одну строку для предполагаемого HTTP-вызова и одну для SSH-команды, а затем заполните обе одинаковыми фактами. Расплывчатые формулировки вроде «доступ на чтение» или «доступ для обслуживания» не подходят.
Используйте сравнение из пяти пунктов:
- Укажите точный результат, например «получить состояние развёртывания для сервиса A» или «перезапустить worker-17 после неудачной проверки здоровья».
- Назовите все доступные цели: коллекции API, проекты, хосты, службы, файлы и сетевые назначения.
- Перечислите изменения, которые та же учётная запись всё ещё может выполнять помимо нужного результата.
- Опишите, какие доказательства останутся после тайм-аута, отказа или мнимого успеха.
- Определите границу подтверждения: один запуск, один вызов или заранее одобренная процедура с фиксированной идентичностью.
Выбирайте HTTP, если его строка описывает меньший набор целей, более узкую операцию и более ясную запись. Выбирайте SSH, если удалённый получатель может обеспечить это лучше API или если для нужной операции на хосте API нет. Если ни один вариант не достаточно узок, пока не подключайте агента. Сначала создайте недостающую конечную точку или программу-получатель.
Такое сравнение выявляет и распространённый плохой совет: «используйте SSH для чтения, а API для записи». Он кажется разумным, потому что shell-доступ воспринимается как операционный, а вызов API как транзакционный. Но чтение хоста может раскрыть учётные данные, исходный код, данные клиентов и топологию, а тщательно ограниченное изменение через API может менять ровно одно желаемое состояние. Чтение и запись недостаточно точно описывают риск. Важны доступные данные и побочные эффекты.
Команде, которая использует агента для диагностики сбоев сборки, может понадобиться конечная точка HTTP для состояния задания, вызов API для получения ограниченного фрагмента лога и удалённый получатель только на одном хосте, когда требуется конкретное исправление. Интерфейсов станет больше, зато обычная диагностика не будет постоянно носить shell-учётные данные только потому, что редкое исправление их требует.
Подтверждение должно соответствовать цене ошибки
Подтверждение полезно, когда появляется на границе, понятной человеку. Если спрашивать о каждом безобидном чтении состояния, люди привыкнут нажимать кнопку, не глядя. Если выдать одно широкое разрешение на все будущие исполняемые файлы, проверка полностью потеряет смысл.
Используйте подтверждение на запуск, когда новый процесс агента впервые просит выполнить действие и его идентичность можно ясно показать. Человек сможет сравнить запрашивающую программу с ожидаемой работой. Если поведение окажется неожиданным, отзовите запуск и изучите предыдущие вызовы по записи действий.
Подтверждение каждого вызова нужно для необратимых или дорогих последствий: смены учётных данных, удаления, продвижения в рабочую среду, изменений аккаунта и всего, чью цель агент может выбирать динамически. В запросе на подтверждение обычными словами назовите назначение и операцию. Фраза «выполнить запрос инструмента» почти ничего не говорит проверяющему.
Не пытайтесь заменить это суждение огромным языком правил для всех исключений. В итоге команда начинает поддерживать вторую среду программирования, чьи крайние случаи разрешают именно то, что хотели заблокировать. Небольшой набор фиксированных средств легче проверять: состояние блокировки хранилища, разрешение на запуск и при необходимости подтверждение каждого использования чувствительных учётных данных.
Подтверждение не компенсирует неограниченные полномочия учётной записи. Оно даёт человеку шанс остановить действие до его выхода с машины. Сам сервис всё равно должен проверять авторизацию, а журнал аудита должен сохранять произошедшее после подтверждения.
Создайте границу удалённых действий до первого инцидента
Лучшее первое изменение обычно связано не с усложнением запроса агента. Замените одну широкую учётную запись одной границей действий с описанной грамматикой ввода, ограниченным набором целей, планом тайм-аутов и доказательствами, которые сможет проверить другой оператор.
Для задачи HTTP попросите владельца сервиса создать конечную точку и учётные данные, разрешения которых соответствуют одному действию. Проверяйте отклонённые пути и методы так же тщательно, как успешные вызовы. Для SSH создайте отдельную учётную запись, отключите интерактивные функции, принудительно запускайте программу-получатель и проверяйте на ней некорректные данные. Выполняйте тесты из того же маршрута, которым будет пользоваться агент: сетевой доступ и проверки идентичности часто отличаются от настроек ноутбука администратора.
Затем проверьте сбой, который никто не любит моделировать: завершите удалённую работу и разорвите соединение до того, как ответ дойдёт до вызывающей стороны. Если агент не может по сохранённой записи и удалённому состоянию определить, нужно ли ждать, запрашивать состояние или повторять действие, под нагрузкой система будет дублировать работу.
Выбор протокола становится простым, если требовать этих свойств. Используйте интерфейс, который предоставляет минимальную именуемую возможность, даёт надёжный ответ после сбоя и оставляет историю действия, не зависящую от чьей-то памяти о работе в терминале.
Вопросы и ответы
Когда AI-агенту следует использовать HTTP вместо SSH?
Используйте HTTP, когда задачу можно представить как узкую операцию с ресурсом, которую сервис способен самостоятельно аутентифицировать, авторизовать, проверить и записать. SSH подходит, когда задаче действительно нужны действия на уровне хоста или удалённая программа, для которой нет подходящего API.
Всегда ли SSH слишком опасен для AI-агента?
SSH не обязательно означает полный доступ к оболочке, но именно так часто получается, когда команды копируют настройку ключа администратора. Ограничьте учётную запись, принудительно запускайте одну команду, отключите перенаправление и проверяйте аргументы до выполнения. Только после этого SSH можно считать достаточно безопасным для конкретной задачи.
Устраняют ли токены API с ограниченной областью весь радиус поражения?
Области действия API ограничивают возможности только тогда, когда API действительно проверяет их для доступных агенту конечной точки и метода. Операции чтения и изменения, создание токенов и экспорт часто защищены разными разрешениями. Проверяйте каждую возможность, а не доверяйте одному названию области.
Что должны записывать журналы действий агента?
Полезная запись должна указывать процесс агента, идентификатор учётных данных, назначение, запрос или команду, результат авторизации и итог операции. Для изменений сохраняйте идентификатор ресурса и значение для корреляции запросов, чтобы оператор мог восстановить ход события.
Может ли агент безопасно повторить удалённое действие после тайм-аута?
Тайм-аут лишь показывает, что клиент не получил ответ. Удалённая сторона могла завершить операцию, продолжать её или отклонить после разрыва соединения. Повторяйте действие только после проверки его идемпотентности и запроса ожидаемого состояния.
Как измерить радиус поражения SSH-команды?
Рассматривайте команду как отдельную возможность с собственной грамматикой ввода, пользователем операционной системы, рабочим каталогом и доступной сетью. Команда, принимающая произвольные пути, фрагменты оболочки или переменные окружения, даёт гораздо больше полномочий, чем предполагает её короткое название.
Нужно ли подтверждать каждый вызов API агента?
Подтверждение должно относиться к конкретному исполняемому процессу и прекращаться после его завершения. Разрешение для всех будущих процессов убирает границу, которая позволяет заметить новый или подменённый агент до начала его работы.
Безопасны ли для агентов разрешения API только на чтение?
Обычно нет. Доступ на чтение может раскрыть исходный код, данные клиентов, конфигурацию или секреты, случайно сохранённые не в том месте. Выдавайте доступ только к нужному набору коллекций или конечных точек и отделяйте обнаружение данных от их экспорта.
Когда SSH лучше подходит для автоматизации?
Используйте SSH, когда в API нет нужной операции, требуются локальные сведения о хосте или уже существует контролируемая программа обслуживания, которая предоставляет более безопасный интерфейс. Не выбирайте SSH лишь потому, что команду оболочки быстрее написать, чем клиент API.
Чем защищённый от подделки журнал аудита отличается от обычных логов?
Журнал аудита должен противостоять незаметным изменениям и ясно показывать, кто разрешил и выполнил действие. Обычные журналы приложения полезны для отладки, но администратор или скомпрометированный процесс часто может изменить или удалить их без следов.