Переменные окружения прокси: проверьте трафик API-агента
Проверьте переменные окружения прокси до того, как AI-агенты начнут обращаться к внутренним API. Убедитесь в правильном наследовании, протестируйте сопоставление NO_PROXY и исключите небезопасные маршруты прокси.

Переменные окружения прокси это исполняемые инструкции по маршрутизации, а не безобидные настройки shell. Если AI-агент для программирования получает HTTP_PROXY, HTTPS_PROXY, ALL_PROXY или NO_PROXY, запрос, который выглядел как прямой вызов внутреннего API, может пройти по другому сетевому маршруту еще до того, как агент успеет сделать что-либо полезное.
Я видел, как команды днями проверяли область действия токенов и списки разрешенных адресов, а потом обнаруживали, что среда запуска агента унаследовала локальный прокси для отладки из shell разработчика. Учетные данные были действительными, клиент API работал ровно как настроено, но трафик все равно уходил не туда, куда рассчитывали. Проверьте окружение процесса до того, как предоставлять агенту доступ к внутренним сервисам.
Переменные прокси меняют маршрут, а не только настройки подключения
Переменная прокси сообщает совместимому клиенту, что запрос нужно передать посреднику. Для обычного HTTP клиент обычно отправляет посреднику полный URL назначения. Для HTTPS клиент обычно просит прокси открыть туннель CONNECT к целевому узлу, а затем устанавливает TLS внутри этого туннеля.
Это важно, потому что прокси может влиять на доступность, контроль назначения, работу DNS и наблюдаемость, даже если он не умеет расшифровывать HTTPS. Прокси может отказать в подключении, перенаправить его на уровне TCP, записать запрошенные узел и порт или стать единственным путем, по которому агент может добраться до сервиса.
Считайте эти переменные частью полномочий агента на исходящие подключения:
HTTP_PROXYиhttp_proxyобычно влияют на URLhttp://.HTTPS_PROXYиhttps_proxyобычно влияют на URLhttps://.ALL_PROXYиall_proxyслужат запасным вариантом в клиентах, которые их поддерживают.NO_PROXYиno_proxyобычно исключают адреса назначения из проксирования.
Слово «обычно» здесь важно. Переменные окружения это соглашение, а не сетевой стандарт, который все среды выполняют одинаково. Агент может вызвать клиент командной строки, использовать HTTP-библиотеку языка, запустить менеджер пакетов или вспомогательный процесс. Каждый уровень может самостоятельно принимать решение о прокси.
Отсутствие переменной тоже не доказывает прямой маршрут. Клиент может прочитать файл конфигурации, использовать системную настройку прокси, подчиниться PAC-файлу или явно вызвать локальный ретранслятор. В этой статье мы сосредоточимся на переменных окружения, потому что их легко унаследовать, трудно заметить среди множества параметров процесса и часто считают временными даже после того, как они стали постоянными.
Средство запуска определяет, что унаследует агент
Агент получает только те переменные, которые есть в его собственном окружении процесса или которые передал родительский процесс. Терминал, где вы проверяли env, может не иметь никакого отношения к процессу, фактически запускающему агента.
В macOS особенно легко ошибиться. Процесс, запущенный из интерактивного shell, получает экспортированные переменные shell. Графическое приложение, запущенное через Finder, или служба, запущенная через launchd, используют другой путь наследования. IDE может запускать встроенный терминал с одним окружением, а хост расширений с другим. Фоновый агент, запущенный вчера, может хранить старое значение прокси еще долго после исчезновения переменной из shell.
Перед изменением настроек составьте карту цепочки запуска. Ответьте на четыре конкретных вопроса:
- Какой процесс запускает агента?
- Запускает ли агент shell, инструменты работы с пакетами, тестовые среды или удаленные помощники?
- Какие из этих процессов выполняют HTTP-запросы?
- Какая точка запуска передает каждую переменную окружения?
Не считайте ответ «агент работает в моем терминале» достаточным, пока не определите родительский процесс и не воспроизведете запуск из этого терминала. Агент может быть дочерним процессом редактора, исполнителя задач или сервиса автоматизации, который использует сохраненное окружение.
Переменная прокси, добавленная родительским процессом, попадает во все дочерние процессы, если только дочерний процесс ее не удалит. Поэтому одна строка экспорта в shell может незаметно изменить запросы, выполняемые установкой пакетов, помощниками системы контроля версий, облачными CLI, автоматизацией браузера и тестовыми фикстурами. Затронутым может оказаться вовсе не тот запрос, о котором вы думали, запуская агента.
Семантика переменных прокси различается у клиентов
Единой трактовки HTTP_PROXY, HTTPS_PROXY и NO_PROXY не существует. Проверка безопасности, в которой поведение одного клиента автоматически приписывают другому, неполна.
В документации curl описано важное исключение, которое многие упускают: curl принимает только http_proxy в нижнем регистре для настройки HTTP-прокси. В документации объясняется, что это защищает от проблемы CGI, когда входящий заголовок Proxy: может превратиться в переменную окружения HTTP_PROXY. Для нескольких других переменных прокси curl принимает варианты в верхнем регистре, но это исключение для HTTP сделано намеренно.
Go описывает http.ProxyFromEnvironment как функцию, читающую HTTP_PROXY, HTTPS_PROXY и NO_PROXY, а также варианты в нижнем регистре. В ней тоже есть защита CGI: если в окружении CGI присутствует REQUEST_METHOD, Go отказывается использовать HTTP_PROXY, потому что его мог передать заголовок запроса. Это не значит, что процесс Go безопасен. Нужно по-прежнему проверить HTTPS_PROXY, варианты в нижнем регистре, явные настройки транспорта и контексты, не связанные с CGI.
Многие приложения на JavaScript еще сильнее усложняют картину. Встроенные HTTP API среды Node.js исторически не задавали единой политики работы с прокси через окружение. Приложения и их зависимости часто добавляют поддержку прокси самостоятельно. Одна команда может учитывать HTTPS_PROXY, другая в том же запуске агента может ее игнорировать, а третья читать отдельный пользовательский параметр.
Не пытайтесь решить это таблицей общеизвестных особенностей сред выполнения. Определите каждый исполняемый файл, способный выполнять сетевые запросы, и протестируйте его. Запишите версию исполняемого файла, команду запуска, целевой URL, соответствующие переменные и факт прямого подключения или подключения через нужный прокси. Храните результат вместе с заметками о развертывании агента, потому что обновление зависимости может изменить поведение.
Часто смешивают два разных понятия: осведомленность о прокси и принудительное использование прокси. Клиент, который учитывает переменную прокси, может направить запрос через прокси, если переменная задана. Но он все равно способен подключиться напрямую, если переменная отсутствует, имеет неверный формат, обходится через NO_PROXY или игнорируется вспомогательным процессом. Если нужно запретить прямой выход в сеть, обеспечьте это на сетевой границе, а не надеясь, что каждая библиотека прочитает переменную окружения.
Для внутренних имен нужны явные тесты NO_PROXY
NO_PROXY это список обхода прокси, и некорректный список может отправить внутренний трафик через прокси или, наоборот, пустить его напрямую, когда вы рассчитывали на проверку. Ни один из этих вариантов нельзя считать безопасным без проверки.
Большинство реализаций принимает записи, разделенные запятыми. Дальше начинаются различия. Клиенты могут по-разному обрабатывать registry.corp.example, .corp.example, corp.example, 10.20.0.0/16, 10.20.30.40, localhost и *. Сопоставление суффикса, работающее в одном клиенте, может оказаться слишком широким или полностью не работать в другом. Записи с указанным портом также ведут себя неодинаково.
Не используйте широкие записи, пока тест не подтвердит их смысл. Голый суффикс домена может исключить узлы, которые вы не собирались исключать. Звездочка может отключить проксирование гораздо шире, чем ожидает проверяющий. Поддержка CIDR полезна там, где она есть, но нельзя считать ее универсальной. Точные внутренние имена узлов выглядят скучно, и в данном случае это хорошо.
Начните с короткого списка именованных сервисов, которые должны подключаться напрямую, например внутреннего узла исходного кода, реестра артефактов и точки обнаружения сервисов. Добавляйте суффикс домена только после того, как убедитесь, что клиент сопоставляет его ожидаемым образом и что всем узлам внутри этого суффикса нужен один и тот же маршрут.
Отдельно проверяйте сопоставление имени и разрешение имени. Клиент часто решает, применять ли NO_PROXY, до подключения. Если в списке указано имя узла, сопоставление может пройти успешно, даже если это имя разрешается в адрес за пределами ожидаемого диапазона. Если в списке указан диапазон IP, клиенту может понадобиться сначала разрешить имя, чтобы принять решение. Последовательность определяет конкретная реализация.
Для теста обхода нужен адрес назначения, которым вы управляете и который можно однозначно найти в журналах. Не используйте рабочий API и не делайте вывод по ответу 200. Внутренняя тестовая точка должна сообщать удаленный адрес или записывать идентификатор запроса в журнал доступа. Затем сравните запрос с присутствующей записью обхода и запрос без нее. Вам нужны доказательства сетевого пути, а не догадка по результату приложения.
HTTPS скрывает содержимое, но прокси все равно получает важные данные
HTTPS-туннель CONNECT обычно защищает заголовки и тела запросов от обычного прямого прокси. Но это не делает прокси несущественным. Он видит узел и порт, указанные в запросе CONNECT, время подключения, объем переданных данных и часто исходный адрес. В зависимости от клиента и сети дополнительную информацию может раскрыть связанный DNS-трафик.
Прокси может прочитать расшифрованные учетные данные API, если клиент доверяет центру сертификации, который прокси использует для перехвата TLS. Такое бывает в некоторых корпоративных сетях и конфигурациях отладки. Наличие доверенного локального корневого сертификата это решение о границе безопасности, а не просто настройка удобства. Если процесс агента доверяет этому корню, оператор прокси может просматривать трафик к любому узлу, на который распространяется политика перехвата.
Обычный HTTP еще опаснее. Прямой прокси может получить полный URL и заголовки запроса, включая токены bearer или данные базовой аутентификации. Не разрешайте агенту использовать незашифрованный HTTP для аутентифицированных внутренних API под предлогом, что «сеть приватная». Переменные окружения прокси это один из способов, которыми предположения о приватной сети оказываются неверными.
Менее очевидная проблема связана с URL прокси, содержащим учетные данные, например http://user:[email protected]:8080. Такое значение может попасть в диагностический вывод, отчеты о сбоях, историю shell, список процессов или журналы, где записывается окружение. Для аутентификации прокси используйте управляемый механизм, подходящий вашей среде, а учетные данные прокси при проверке безопасности считайте самостоятельными секретами.
Если вы не можете определить оператора прокси, адрес его прослушивания и возможность перехвата TLS, не направляйте через него привилегированный трафик агента. Это не паранойя. Прокси уже стал частью пути между автоматизированным процессом и чувствительным сервисом.
Проверьте работающий процесс, не раскрывая его секреты
Начните с инвентаризации, которая показывает имена переменных и адреса прокси, но не выводит все окружение целиком. В shell, из которого может запускаться агент, выполните:
env | grep -Ei '(^|_)(http|https|all|no)_proxy='
Вывод должен выглядеть примерно так:
HTTPS_PROXY=http://127.0.0.1:8888
NO_PROXY=localhost,127.0.0.1,registry.corp.example
Если URL прокси содержит сведения о пользователе, не вставляйте исходный вывод в заявку. Запишите схему, узел и порт после удаления учетных данных. Loopback-адрес не гарантирует безопасность. Локальные прокси часто принадлежат легитимным инструментам отладки, но на loopback также могут прослушивать порт вредоносные или нежелательные программы. Проверьте, какой процесс владеет портом.
В macOS просмотреть слушающий процесс можно так:
lsof -nP -iTCP:8888 -sTCP:LISTEN
Обычный результат показывает команду и идентификатор процесса. Если ожидаемый процесс не владеет портом, остановитесь и разберитесь. Не направляйте учетные данные агента в процесс только потому, что его адрес начинается с 127.0.0.1.
Затем проверьте сам процесс агента. ps в macOS может показать окружение процесса, но заодно раскрыть посторонние секреты. Ограничьте доступ владельцем компьютера или администратором, собирайте только необходимые данные и не вставляйте результат в чат или общий журнал.
ps eww -p "$AGENT_PID" | tr ' ' '\n' | grep -Ei '(^|_)(http|https|all|no)_proxy='
Задайте AGENT_PID как идентификатор работающего процесса агента. Эта команда все еще может вывести чувствительные учетные данные прокси, если они есть, поэтому выполняйте ее в доверенном терминале и удаляйте секреты перед сохранением свидетельств. Если вывод отличается от проверки shell, родительский процесс добавил или удалил переменные.
Для процессов, запущенных через launchd, проверяйте описание задания и средство запуска, а не полагайтесь на терминал. Команда launchctl getenv HTTPS_PROXY может показать переменную в текущем домене launchd, но ее отсутствие не снимает подозрений с конкретного задания. Задание может задавать собственное окружение, а скрипт-обертка экспортировать переменные непосредственно перед запуском агента.
Подтвердите маршрут безопасным запросом
Проверка конфигурации показывает, что должно происходить. Контролируемый запрос показывает, что произошло на самом деле. Нужны оба вида проверки.
Создайте или используйте нечувствительную точку, которая записывает адрес узла-партнера и путь запроса. Затем выполните запрос с подробным выводом соединения. curl удобен тем, что показывает подключение через прокси и отправку запроса CONNECT.
HTTPS_PROXY=http://127.0.0.1:8888 \\
NO_PROXY= \\
curl -v --connect-timeout 5 https://probe.corp.example/agent-proxy-check
Когда curl использует прокси для HTTPS, подробный вывод обычно содержит строки такого вида:
* Uses proxy env variable HTTPS_PROXY == 'http://127.0.0.1:8888'
* Establish HTTP proxy tunnel to probe.corp.example:443
> CONNECT probe.corp.example:443 HTTP/1.1
Затем намеренно выполните прямое сравнение:
HTTPS_PROXY=http://127.0.0.1:8888 \\
NO_PROXY=probe.corp.example \\
curl -v --connect-timeout 5 https://probe.corp.example/agent-proxy-check
При прямом подключении должен отображаться контакт с целевым узлом, а не запрос CONNECT к прокси. Подтвердите результат в журналах тестового сервера. Если curl сообщает об обходе прокси, но сервер видит неожиданный источник или запрос не выполняется, отдельно проверьте DNS, маршрутизацию и возможный прозрачный сетевой прокси.
Это доказывает поведение curl, а не вашего агента. Повторите тест через точный маршрут запуска агента. Если он вызывает скрипт, запустите этот скрипт. Если он использует зависимость для вызова API, временно добавьте URL для проверки через ту же конфигурацию. Если он запускает вспомогательный процесс, соберите свидетельства маршрута этого процесса. Тест другого клиента дает лишь подсказку.
Не используйте для этого публичный сервис «какой у меня IP». Так проверка внутренней маршрутизации превращается в ненужное раскрытие данных вовне, а сам сервис не покажет, какая внутренняя политика прокси сработала.
Чистое окружение запуска лучше постоянных экспортов в shell
Не добавляйте корпоративные экспорты прокси в общий профиль shell, ожидая, что автономные инструменты сами будут безопасно делать исключения. Глобальные экспорты популярны, потому что однажды помогают выполнить заблокированную команду. Но они также распространяются на каждый дочерний процесс, о котором вы потом забудете.
Используйте явное средство запуска агента. Начинайте с известного окружения, передавайте только нужные переменные и сделайте использование прокси видимым в команде запуска или обертке. В Unix-shell команда env -i очищает унаследованные переменные, поэтому нужно вернуть базовые параметры, необходимые программе:
env -i \\
PATH="$PATH" \\
HOME="$HOME" \\
LANG="${LANG:-en_US.UTF-8}" \\
NO_PROXY="localhost,127.0.0.1,registry.corp.example" \\
agent-command
В этом примере прокси намеренно не задан. Если агенту он нужен, добавьте переменную прокси в средство запуска после того, как установите владельца прокси и проверите его поведение. Не копируйте значение прокси из профиля shell в скрипт, не выяснив, содержит ли оно учетные данные и не указывает ли на устаревшую локальную службу.
Чистое окружение может нарушить работу инструментов, которые рассчитывали на такие переменные, как пути к сертификатам, профили облачных сервисов, сокеты SSH-агента или кэши пакетов. Это полезная информация. Возвращайте нужные агенту переменные по одной и документируйте причину каждой. Средство запуска агента должно быть достаточно узким, чтобы другой инженер мог прочитать его и понять, куда пойдут запросы.
Сетевые средства контроля должны дополнять этот подход. Если агенту разрешено обращаться только к нескольким внутренним сервисам, используйте правила межсетевого экрана, прокси для исходящего трафика с принудительной политикой или отдельный сетевой сегмент, подходящий вашей среде. Переменные окружения выбирают маршрут для совместимых клиентов. Они не мешают скомпрометированному процессу или несоответствующей библиотеке открыть прямой сокет.
Не храните учетные данные в процессе, который выбирает маршрут
Гигиена прокси снижает риск случайной смены маршрута, но не делает разумной передачу API-токенов автономному агенту. Если в окружении агента есть токен bearer, каждый процесс, имеющий доступ к этому окружению, становится частью пути раскрытия секрета.
Sallyport использует другую границу: агент запрашивает HTTP- или SSH-действие через MCP shim, а учетные данные остаются в зашифрованном хранилище приложения, которое и выполняет действие. Это ограничивает последствия утечки переменной прокси в процессе агента, потому что агент никогда не получает API- или SSH-учетные данные в открытом виде.
Не переоценивайте эту границу. Шлюз учетных данных не задает автоматически безопасное поведение прокси для каждой команды, которую запускает агент, и не превращает опасное назначение в безопасное. По-прежнему нужно контролировать разрешенные назначения и действия, проверять процесс приложения, выполняющий сетевой вызов, и сохранять свидетельства маршрута запроса.
Полезно разделять хранение секретов и сетевую маршрутизацию. Хранение секретов отвечает на вопрос, кто может прочитать учетные данные. Сетевая маршрутизация отвечает на вопрос, какой посредник обрабатывает запрос. Команды часто решают одну проблему и считают, что решили обе. Это не так.
Рассматривайте необъяснимое использование прокси как инцидент, который нужно локализовать
Если привилегированный агент отправлял запросы через неизвестный прокси, остановите запуск до начала расследования из того же потенциально скомпрометированного окружения. Запишите идентификатор процесса агента, его родительский процесс, адрес прокси, затронутые имена назначений и временной интервал. Сохраните относящиеся к делу журналы агента и прокси в соответствии с процедурой реагирования на инциденты.
Затем удалите переменную в источнике. Удаление в текущем терминале исправит только будущие дочерние процессы этого терминала. Проверьте профили shell, настройки задач IDE, launch agents, конфигурацию CI, скрипты-обертки и все средства управления конфигурацией, записывающие параметры окружения. После исправления точки запуска перезапустите затронутый процесс.
Оцените учетные данные с учетом протокола. Если затронутый трафик был обычным HTTP с аутентификацией, замените раскрытые учетные данные. Если это был HTTPS через прокси, выясните, проверял ли узел обычный TLS и доверял ли агент сертификату для перехвата. Не считайте автоматически, что HTTPS не требует проверки, и не меняйте учетные данные вслепую, оставляя тот же путь внедрения переменных.
Наконец, добавьте предварительную проверку в точку запуска агента. Останавливайте запуск или требуйте явного подтверждения, если появляется неожиданная переменная прокси. Проверка должна сообщать имя переменной и очищенный от секретов адрес, сравнивать его с разрешенным маршрутом для этой задачи и оставлять запись о выполнении. Первый необъяснимый прокси это предупреждение. Второй это дефект развертывания, который вы решили сохранить.
Вопросы и ответы
Для чего нужны HTTP_PROXY и HTTPS_PROXY?
Они указывают совместимым HTTP-клиентам отправлять запросы через прокси вместо прямого подключения к адресу назначения. Эти переменные не заставляют каждую программу подчиняться им, поэтому нужно тестировать самого агента, его инструменты и дочерние процессы.
Может ли HTTPS-прокси прочитать токены API?
Иногда. Прокси, обслуживающий HTTPS-туннель CONNECT, обычно видит имя узла назначения и порт, но не видит зашифрованное тело запроса. Он может прочитать HTTPS-трафик только в том случае, если клиент доверяет центру сертификации, который позволяет прокси перехватывать TLS, либо если клиент передает чувствительные данные до начала TLS.
Для чего используется NO_PROXY?
NO_PROXY это список исключений. Он сообщает многим клиентам, что к указанным узлам, доменам или IP-адресам нужно подключаться напрямую. Точные правила сопоставления зависят от библиотеки клиента и ее версии.
Поддерживает ли NO_PROXY маски для доменов?
Не предполагайте, что начальная точка, отдельный суффикс, блок CIDR или звездочка означают одно и то же во всех программах. Проведите прямые тесты с точной командой или библиотекой, которую использует агент, а затем оставьте список коротким и явным.
Почему переменные прокси опасны для AI-агентов?
Если процесс агента получает адрес прокси из shell, IDE, CI-исполнителя или менеджера служб, его запросы могут уйти через этот маршрут без какого-либо запроса подтверждения. Риск особенно высок, если прокси принадлежит VPN-помощнику, инструменту отладки, настройке гостиничной сети или неизвестному локальному процессу.
Как проверить настройки прокси в macOS?
Начните с инвентаризации без секретов: env | grep -Ei '(^|_)(http|https|all|no)_proxy='. Затем проверьте средство запуска и окружение процесса, установите владельца прокси и адрес прослушивания и подтвердите маршрут безопасным запросом до того, как разрешать доступ к внутренним сервисам.
Все ли HTTP-клиенты учитывают переменные окружения прокси?
Нет. curl, Go, Python, Java, пакеты Node и утилиты командной строки самостоятельно решают, как работать с переменными окружения. Одни учитывают имена в верхнем и нижнем регистре, другие имеют защиту для CGI, а третьим нужна отдельная настройка прокси.
Предотвращает ли NO_PROXY утечки через DNS?
Прямое подключение все равно может раскрыть имя узла через DNS, если резолвер находится за пределами ожидаемой сетевой границы. Оно также может не сработать из-за отсутствия прямого маршрута. Поэтому прямой тест должен проверять и TCP-маршрут, и ответ приложения.
Что делать, если агент использовал неизвестный прокси?
Если маршрут изменился для чувствительного трафика или неизвестный прокси получил запросы, отнеситесь к этому как к инциденту. Остановите агента, удалите унаследованные переменные в фактической точке запуска, отзовите учетные данные, которые могли пройти по ненадежному HTTP-маршруту, и сохраните журналы процессов и прокси.
Устраняет ли шлюз учетных данных риски, связанные с настройкой прокси?
Нет. Шлюз может оставить API- и SSH-учетные данные за пределами процесса агента, что снижает риск их раскрытия, но он не решает автоматически, как каждый сторонний клиент обрабатывает переменные прокси. Вам по-прежнему нужны чистое окружение запуска и проверенный сетевой маршрут.