«Браузер открывает внешние сайты, а деловое приложение не достигает внешнего API.» «На машине разработки работает, а в сети заказчика уходит в тайм-аут.» «Общается, когда запускаю вручную, и падает, как только превращаю в службу Windows.» — Когда вы запускаете деловое приложение в среде с корпоративным прокси, такие обращения среди самых частых.
В большинстве случаев причина — не отказ прокси-сервера и не ошибка приложения. В Windows есть несколько отдельных семейств того, что люди называют «настройками прокси», и какие настройки кто читает, различается по приложению (по HTTP-стеку, который оно использует) и по учётной записи выполнения — это расхождение. Настройки, которые читает браузер, которые читает служба и которые читает HttpClient .NET, могут каждая быть разной вещью. Как только эта структура в голове, изолировать «в браузере работает, но…» становится на удивление быстро.
Статья рассчитана на ИТ-сотрудников малых и средних компаний и разработчиков приложений Windows. Она связывает в одну картину три семейства настроек прокси — WinINET, WinHTTP и переменные окружения — автоконфигурацию PAC и WPAD, разницу разрешения прокси между .NET Framework и .NET (Core и новее), аутентифицирующие прокси (407), TLS-инспекцию и практическую процедуру изоляции. Шаблоны создания HttpClient и проектирование тайм-аутов сами по себе разобраны в «Не оборачивайте HttpClient в using», поэтому эта статья сосредоточена на разрешении прокси.
1. Сначала вывод
- Настройки прокси Windows — не одна вещь; есть как минимум три семейства. (1) Пользовательские настройки WinINET (страница «Прокси» в приложении «Параметры» = старые параметры Интернета), (2) машинные настройки WinHTTP (
netsh winhttp) и (3) переменные окруженияHTTP_PROXY/HTTPS_PROXY. Какое читается, решает сторона приложения.12 - «Прокси», который вы видите в «Параметрах», — это пользовательские настройки WinINET. Браузеры и интерактивные приложения их читают; службы Windows — нет. WinINET не поддерживается для использования в службе; служебное использование — работа WinHTTP.13
- Самая частая причина «вручную работает, как служба нет» — разница учётной записи выполнения. LocalSystem и учётная запись службы не видят пользовательский прокси, который администратор настроил на своём экране.34
netsh winhttp set proxy— статическая настройка; она не обрабатывает PAC, автообнаружение и аутентификацию прокси. Если хотите настроить PAC или WPAD на машину, нужна сторонаnetsh winhttp set advproxy.42- Результаты PAC меняются по URL. Функция
FindProxyForURLфайла PAC принимает URL и узел и возвращает список прокси или прямое соединение (DIRECT). «Тот сайт работает, а только этот API нет» может быть веткой PAC.56 - HttpClient в .NET (Core и новее) инициализирует прокси по умолчанию в порядке переменные окружения → пользовательские настройки прокси Windows. Если задана любая из
HTTP_PROXY,HTTPS_PROXYилиALL_PROXY, она имеет приоритет над настройками ОС, поэтому случается авария «кто-то оставил переменную окружения».7 - Стандарт .NET Framework — параметры Интернета учётной записи выполнения, и его можно переопределить
defaultProxyв app.config. Настройки файла конфигурации имеют приоритет над системными.89 - 407 — ошибка аутентификации прокси; это иное, чем 401 (аутентификация сервера). Схемы включают Negotiate, NTLM и Basic, а в .NET учётные данные передают через
DefaultProxyCredentialsилиWebProxy.UseDefaultCredentials. Следите за тем, что под учётной записью службы содержимое «учётных данных по умолчанию» меняется.101112 - Прокси TLS-инспекции держится только в комплекте с раздачей внутреннего сертификата УЦ. Машины и среды выполнения, которые его не получили, получают ошибку проверки сертификата. Решайте раздачей в хранилище сертификатов, а не отключением проверки в приложении.134
Одним предложением: каждый раз, когда вы говорите «я проверил настройки прокси», всегда умейте сказать, какое из трёх семейств вы проверили и из какой учётной записи — такова тема этой статьи.
2. В Windows три семейства «настроек прокси»
Сначала общая карта. Пути, которыми приложение Windows ищет корпоративный прокси, попадают в эти три семейства.
| Семейство настроек | Где задаёте / команда | Область | Кто в основном читает |
|---|---|---|---|
| (1) WinINET (параметры Интернета) | Параметры → Сеть и Интернет → Прокси, inetcpl.cpl |
На пользователя (по умолчанию) | Браузеры, интерактивные настольные приложения, стандарт .NET Framework |
| (2) WinHTTP (машинные настройки) | netsh winhttp set proxy / set advproxy |
Машина | Службы Windows, некоторые компоненты ОС |
| (3) Переменные окружения | HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY |
Процесс (наследуются в зависимости от места определения) | HttpClient в .NET (Core и новее), curl, кроссплатформенные инструменты вроде Node.js и Python |
(1) — то, что люди обычно узнают как «настройки прокси Windows»; суть — конфигурация WinINET. Исторически это параметры Интернета Internet Explorer, и по умолчанию они хранятся на пользователя.4
(2) — машинный стандарт для контекстов вроде службы, где «нет вошедшего пользователя». (3) — в основном соглашение инструментов из кроссплатформенного мира; в Windows их также читают .NET (Core и новее) и curl и подобные.7
Важный момент: какое семейство читается, решает сторона приложения, а не сторона настроек. Если приложение внутри использует WinINET, оно читает (1); если WinHTTP — (2) (или переопределение самого приложения); если .NET (Core и новее) — (3), затем (1). Так что обычно это не «настройки прокси верны, но всё равно не подключается»; реальность — «семейство, которое читало приложение, было другим семейством, чем то, которое вы проверили».
flowchart TB
accTitle: Три семейства настроек прокси Windows
accDescr: WinINET — пользовательские Параметры и параметры Интернета, WinHTTP — машинный стандарт через netsh, переменные окружения — область процесса. Какое семейство читается, решает приложение, не сторона настроек
fam{"Какое семейство?"}
fam --> wininet["Пользовательские настройки WinINET"]
fam --> winhttp["Машинные настройки WinHTTP"]
fam --> env["HTTP_PROXY и родственные"]
wininet -.-> r1["Браузеры и настольные приложения"]
winhttp -.-> r2["Службы и части ОС"]
env -.-> r3[".NET Core+ и curl"]
Рис. 1: Три семейства стоят рядом. Приложение выбирает, какое читать.
Если включить групповую политику «Сделать настройки прокси машинными (а не пользовательскими)», можно переключить (1) на машинные и применить те же настройки ко всем пользователям. С MDM (Intune и подобные) можно настроить на устройство через CSP NetworkProxy.4
3. WinINET и WinHTTP — для интерактивных приложений и для служб
3.1. Разница ролей
WinINET и WinHTTP — оба встроенные HTTP-клиентские стеки Windows, но предполагают разное использование.
- WinINET: рассчитан на интерактивные настольные приложения. Автоматически наследует параметры Интернета пользователя (прокси, cookie, кэш учётных данных) и при необходимости может даже показать интерфейс ввода учётных данных. Использование в службе или процессе, подобном службе, не поддерживается.1
- WinHTTP: рассчитан на службы и серверную сторону. Поддерживает выполнение под учётной записью службы, олицетворение потока и изоляцию сеанса; взамен не разделяет настройки браузера пользователя, cookie и учётные данные. Также не показывает интерфейс.3
Собственное руководство Microsoft столь же ясно: «используйте WinINET, если только вы не работаете внутри службы или в процессе, подобном службе, которому нужны изоляция сеанса и олицетворение» — иначе говоря, если это служба, используйте WinHTTP.1
flowchart TB
accTitle: WinINET для интерактивных приложений, WinHTTP для служб
accDescr: WinINET наследует параметры Интернета вошедшего пользователя и не поддерживается в службе. WinHTTP работает под учётной записью службы без интерфейса и не разделяет настройки браузера пользователя
q{"Интерактивное настольное приложение?"}
q -->|"Да"| ie["WinINET"]
q -->|"Служба или подобное"| wh["WinHTTP"]
ie -.-> ieNote["Читает параметры Интернета пользователя"]
wh -.-> whNote["Машинные настройки, без UI"]
Рис. 2: Интерактивные приложения используют WinINET. Служба использует WinHTTP.
3.2. Базовые операции netsh winhttp
Машинный прокси по умолчанию WinHTTP обслуживается через netsh.2
:: Display the current WinHTTP proxy settings
netsh winhttp show proxy
:: Set a static proxy (with a bypass list)
netsh winhttp set proxy proxy-server="proxy.example.co.jp:8080" bypass-list="*.example.co.jp;<local>"
:: Import the Internet Options (WinINET) settings
netsh winhttp import proxy source=ie
:: Return to the default (DIRECT)
netsh winhttp reset proxy
Два ограничения, которые стоит держать в голове.
netsh winhttp set proxy— статическая настройка. Она не обрабатывает ни автообнаружение прокси, ни указание URL PAC, ни аутентификацию прокси.4import proxy source=ieкопирует только статические настройки того момента; он не следует за последующими изменениями на стороне параметров Интернета. Когда нужна машинная конфигурация, включающая PAC или автообнаружение, настройте подробные настройки в форме JSON (Proxy,ProxyBypass,AutoconfigUrl,AutoDetect) черезnetsh winhttp set advproxy.2
3.3. Самая частая ловушка: служба не читает настройки IE пользователя
Шаблон, который чаще всего видят на площадке, во временном порядке выглядит так.
- Разработчик запускает инструмент на своём ПК → его пользовательские настройки прокси (1) вступают в силу и работает
- В продакшене оставляют резидентным как службу Windows (Как создавать и эксплуатировать службы Windows) под LocalSystem
- Настройки, видимые из LocalSystem, — другая вещь (пользовательские невидимы, машинные настройки WinHTTP не заданы = DIRECT) → пытается прямое соединение с внешним API и уходит в тайм-аут
Это не «не работает, хотя та же машина»; даже на той же машине другая учётная запись выполнения означает, что виден другой набор настроек прокси. Для процесса, который общается, даже когда никто не вошёл, правильный подход — подготовить машинные настройки в той форме, которую HTTP-стек этого процесса реально читает. Для собственного приложения или компонента Windows, который использует WinHTTP, действуют настройки WinHTTP netsh.4 HttpClient в .NET (Core и новее), напротив, не читает машинные настройки WinHTTP (см. главу 5), поэтому для службы .NET задайте системную переменную окружения (HTTPS_PROXY и подобные) или явно укажите HttpClientHandler.Proxy из настроек приложения.
Авария случается и в другую сторону. Если запечь статический прокси в ноутбук, который ходит между корпоративной сетью и внешним миром, через netsh winhttp set proxy, этот прокси недоступен вне компании, и связь умирает полностью. Считайте машинную статическую настройку средством, нацеленным на серверы, чья сетевая конфигурация не меняется.4
flowchart TB
accTitle: Почему служба не видит настройки IE пользователя
accDescr: Запуск разработчиком читает пользовательские настройки WinINET и работает. Как LocalSystem эти настройки невидимы. Собственное приложение WinHTTP тогда следует незаданным машинным настройкам (DIRECT). Служба .NET Core+ по-прежнему использует переменные окружения или явный handler.Proxy и не переключается на netsh winhttp
dev["Запуск вручную от пользователя"] --> ok["Применяются пользовательские настройки WinINET"]
svc["Служба Windows как LocalSystem"] --> miss["Пользовательские настройки невидимы"]
miss --> stack{"Какой HTTP-стек?"}
stack -->|"WinHTTP"| direct["WinHTTP не задан = DIRECT"]
stack -->|".NET Core+"| env["Переменные окружения или handler.Proxy"]
direct --> fail["Внешний API уходит в тайм-аут"]
Рис. 3: Та же машина, другая учётная запись, другой видимый набор настроек прокси.
4. PAC и WPAD — чем на самом деле является «автоконфигурация»
4.1. Файлы PAC и FindProxyForURL
Файл PAC (Proxy Auto-Configuration) — это JavaScript (ECMAScript), который вычисляет «какой прокси использовать для этого URL», и всегда содержит функцию с именем FindProxyForURL(url, host). Функция возвращает список прокси, которые следует использовать, или особое возвращаемое значение (DIRECT), означающее, что можно соединяться напрямую без прокси.5
function FindProxyForURL(url, host) {
// Internal domains and private addresses go direct
if (dnsDomainIs(host, ".example.co.jp") ||
isInNet(host, "10.0.0.0", "255.0.0.0")) {
return "DIRECT";
}
// Everything else goes through a proxy. Fall back to the next if the first is unavailable
return "PROXY proxy1.example.co.jp:8080; PROXY proxy2.example.co.jp:8080; DIRECT";
}
Отсюда следуют два практических следствия.
- Разрешение прокси нужно делать по URL. Поскольку PAC может вернуть другой прокси или прямое соединение в зависимости от URL (узла), функция автоматического прокси WinHTTP тоже спроектирована так, чтобы каждый раз передавать URL запроса и запрашивать.6 «Браузер видит другой сайт» — не доказательство, что проблемный API идёт тем же путём.
- DIRECT — указание «идти без прокси». Если трафик, который должен быть внутренним, никогда не появляется в журнале прокси, сначала подозревайте, что PAC вернул DIRECT (или попал в список обхода).
4.2. Автообнаружение через WPAD
Включите «Автоматически определять параметры», и машина ищет расположение файла PAC протоколом WPAD (Web Proxy Auto-Discovery). В типичной конфигурации DHCP выдаёт URL PAC, либо через DNS ищут узел с именем wpad и PAC скачивают с URL вроде http://wpad/wpad.dat.14
Иными словами, «автообнаружение» — не магия; это механизм, который работает только в сети, где уже настроено устройство WPAD в DHCP/DNS. Включить одно автообнаружение в сети без такого устройства — лишь добавить время ожидания сбоя обнаружения.
flowchart TB
accTitle: PAC разрешает прокси по URL, WPAD только находит PAC
accDescr: FindProxyForURL принимает URL и узел и возвращает список прокси или DIRECT. WPAD находит PAC только через DHCP или DNS. Клиент, который не может вычислить PAC, падает на статический прокси или переменные окружения
url["URL запроса"] --> pac["FindProxyForURL"]
pac -->|"список прокси"| via["Идти через прокси"]
pac -->|"DIRECT"| dir["Соединяться без прокси"]
wpad["WPAD через DHCP или DNS"] -.-> pac
nopac["Клиент не вычисляет PAC"] -.-> fb["Статические настройки или переменные окружения"]
Рис. 4: PAC решает по URL. WPAD только находит файл PAC.
4.3. Как ведут себя клиенты, которые не могут вычислить PAC
Не каждый клиент может вычислить PAC.
- Статические настройки
netsh winhttp set proxyне вычисляют PAC.4 - Инструменты в стиле переменной окружения
HTTP_PROXYкак правило могут записать только фиксированный URL прокси (некуда записать URL PAC).7 - Для собственного приложения, которое использует WinHTTP напрямую, зависит от того, как открыта сессия. Приложение, открытое через
WinHttpOpenв Windows 8.1 и новее с указаниемWINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, имеет WinHTTP, который автоматически разрешает системные/пользовательские настройки прокси (включая WPAD/PAC) на каждый запрос.15 Если открыто более старымWINHTTP_ACCESS_TYPE_DEFAULT_PROXY(устарел с 8.1) или подобным, автоматический прокси не интегрирован в HTTP-стек, и приложение должно само вызватьWinHttpGetProxyForUrlи применить результат к запросу. Иными словами, на более старой реализации PAC может быть и всё равно не использоваться.5
«Браузер идёт на правильный прокси через PAC, а деловое приложение не читает PAC и пытается прямое соединение и падает» — ещё одно классическое расхождение. В сети, работающей на PAC, нужно решить запасной путь — статические настройки или переменные окружения — для клиентов, которые не могут читать PAC.
5. Разрешение прокси .NET — Framework и Core и новее это разные вещи
Какие настройки прокси читает приложение .NET, по умолчанию различается между .NET Framework и .NET (Core и новее). Смешайте два — и будете расследовать приложение .NET 8 знаниями эпохи Framework и промахнётесь.
5.1. .NET Framework — стандарт это параметры Интернета, переопределяется defaultProxy
В .NET Framework HttpWebRequest и сидящий на нём HttpClient используют прокси по умолчанию, если не указать Proxy явно. Прокси по умолчанию решается сочетанием интернет-настроек системы (настройки WinINET учётной записи выполнения) и файла конфигурации, и настройки файла конфигурации имеют приоритет.8
Этим стандартом можно управлять элементом system.net/defaultProxy в app.config (или machine.config).9
<configuration>
<system.net>
<!-- useDefaultCredentials: whether to send default credentials to an authenticating proxy -->
<defaultProxy enabled="true" useDefaultCredentials="true">
<proxy usesystemdefault="true"
proxyaddress="http://proxy.example.co.jp:8080"
bypassonlocal="true" />
<bypasslist>
<add address="[a-z]+\.example\.co\.jp$" />
</bypasslist>
</defaultProxy>
</system.net>
</configuration>
Оставьте элемент defaultProxy пустым — используются системные настройки (параметры Интернета); напишите proxyaddress и подобное — они имеют приоритет. Из программы тот же стандарт можно заменить через WebRequest.DefaultWebProxy.98
Ловушка главы 3.3 действует и здесь. Поскольку стандарт — «параметры Интернета учётной записи выполнения», приложение .NET Framework под учётной записью службы читает другой (обычно пустой) набор настроек, чем те, что видны на рабочем столе администратора.
5.2. .NET (Core и новее) — сначала переменные окружения, затем пользовательские настройки ОС
У HttpClient в .NET (Core и новее) есть статическое свойство HttpClient.DefaultProxy. Если обработчик не указывает прокси явно, каждый экземпляр HttpClient его использует. Правило инициализации в Windows: «читать переменные окружения, и если они не заданы, читать пользовательские настройки прокси».7
Используемые переменные окружения таковы.7
| Переменная окружения | Значение |
|---|---|
HTTP_PROXY |
Прокси для HTTP-запросов |
HTTPS_PROXY |
Прокси для HTTPS-запросов |
ALL_PROXY |
Запасной вариант, когда выше не заданы |
NO_PROXY |
Список узлов через запятую, которые не должны использовать прокси |
Три вещи, за которыми следить.
- Если задана любая из
HTTP_PROXY,HTTPS_PROXYилиALL_PROXY, она имеет приоритет над настройками прокси со стороны ОС. Задать толькоNO_PROXYне настраивает прокси из переменных окружения, и в Windows продолжают использоваться пользовательские настройки прокси ОС. «Невидимые настройки» вроде оставленной после старого эксперимента системнойHTTPS_PROXYили шаблона CI/CD, который её внедряет, — рассадник аварий. NO_PROXYне поддерживает подстановочные знаки (*). Чтобы сопоставить поддомен, поставьте ведущую точку (.example.comсопоставляется сwww.example.com, но не с самимexample.com).7- Вне Windows (контейнеры Linux и подобные), если переменные окружения не заданы, инициализируется без прокси. Смена стандартного поведения одного и того же приложения между Windows и Linux — то, что стоит подтвердить при миграции в контейнер.7
5.3. Явное указание — HttpClientHandler.Proxy и UseProxy
На любой среде выполнения наивысший приоритет — явное указание на обработчике. Указание HttpClientHandler.Proxy имеет приоритет над настройками ОС и файлом конфигурации, а UseProxy = false не использует прокси вовсе.14
using System.Net;
// Use a proxy read from app settings explicitly
var handler = new HttpClientHandler
{
Proxy = new WebProxy("http://proxy.example.co.jp:8080")
{
BypassProxyOnLocal = true,
BypassList = new[] { @"^intra\.example\.co\.jp$" },
UseDefaultCredentials = true // On an authenticating proxy, respond with the running account's credentials
},
UseProxy = true
};
var client = new HttpClient(handler);
// A client that never uses a proxy (for direct internal APIs)
var directHandler = new HttpClientHandler { UseProxy = false };
var directClient = new HttpClient(directHandler);
Когда явного указания нет и следуют настройкам ОС, у автоматического обхода локальных назначений есть правила. Плоское имя без точки, адрес петли, назначение, совпадающее с собственным суффиксом домена машины, и подобное могут считаться «локальными».14 Явления вроде «поведение меняется, если указать IP-адрес» или «вдруг пошло через прокси, когда использовал FQDN» могут быть вызваны этим суждением.
Порядок приоритета таков.
| Приоритет (высокий → низкий) | .NET Framework | .NET (Core и новее) |
|---|---|---|
| 1 | Явное указание вроде HttpClientHandler.Proxy |
То же |
| 2 | defaultProxy в app.config |
Присвоение HttpClient.DefaultProxy |
| 3 | Параметры Интернета учётной записи выполнения | Переменные окружения (HTTP_PROXY и другие) |
| 4 | — | Пользовательские настройки прокси Windows |
flowchart TB
accTitle: Разрешение прокси по умолчанию в Framework против Core и новее
accDescr: Явный HttpClientHandler.Proxy всегда побеждает. Framework затем использует app.config defaultProxy и параметры Интернета учётной записи выполнения. Core и новее использует присвоение HttpClient.DefaultProxy, затем переменные окружения, затем пользовательские настройки прокси Windows
expl["Явный handler.Proxy"] --> done["Используется этот прокси"]
noexpl["Нет явного Proxy"] --> fw{"Какая среда выполнения?"}
fw -->|"Framework"| cfg["app.config defaultProxy"]
cfg --> ie["Параметры Интернета учётной записи"]
fw -->|"Core и новее"| dp["HttpClient.DefaultProxy"]
dp --> ev["HTTP_PROXY и родственные"]
ev --> user["Пользовательские настройки прокси Windows"]
Рис. 5: Явное указание всегда побеждает. Путь по умолчанию различается по среде выполнения.
6. Аутентифицирующие прокси — 407 это ошибка аутентификации прокси
6.1. Не путайте 407 с 401
Когда вы пытаетесь пройти через прокси, который требует аутентификации, прокси возвращает код состояния 407 (Proxy Authentication Required) и заголовок Proxy-Authenticate со списком доступных схем. Это иное, чем требование аутентификации сервера назначения (401 и WWW-Authenticate); сторона, которой вы передаёте учётные данные, и место, где вы их настраиваете, обе разные.10
flowchart TB
accTitle: 407 это прокси, 401 это сервер назначения
accDescr: 407 и Proxy-Authenticate приходят от прокси. 401 и WWW-Authenticate приходят от сервера назначения. Учётные данные и место настройки различаются
req["Исходящий запрос"] --> who{"Кто требует аутентификацию?"}
who -->|"Прокси"| e407["407 + Proxy-Authenticate"]
who -->|"Назначение"| e401["401 + WWW-Authenticate"]
e407 -.-> cred["DefaultProxyCredentials"]
Рис. 6: 407 — аутентификация прокси. 401 — аутентификация сервера.
Схемы включают Basic, который отправляет имя пользователя и пароль как есть, и схемы вызов/ответ вроде Negotiate (Kerberos/NTLM). В схеме вызов/ответ сам пароль не идёт по сети, и аутентификация завершается за несколько обменов.10 Механизм, на какую схему он «откатывается», подробнее разобран в «NTLM и Kerberos на схемах».
6.2. Как передать учётные данные в .NET
Когда хотите использовать прокси по умолчанию из настроек ОС и только провести аутентификацию, используйте HttpClientHandler.DefaultProxyCredentials. Это учётные данные, отправляемые тому прокси по умолчанию, когда UseProxy = true и Proxy = null (= системный прокси по умолчанию).11
using System.Net;
var handler = new HttpClientHandler
{
UseProxy = true, // The default. Combined with a null Proxy, this uses the system-default proxy
Proxy = null,
// Respond to 407 with the credentials of the running account (signed-in user or service account)
DefaultProxyCredentials = CredentialCache.DefaultCredentials
};
var client = new HttpClient(handler);
Когда указываете прокси явно, положите учётные данные на сторону WebProxy. Во многих клиентских сценариях рекомендация — использовать учётные данные по умолчанию вошедшего пользователя, а не отдельные имя и пароль, и WebProxy.UseDefaultCredentials = true — это то.12
6.3. Проблема 407 учётной записи службы
Учётная запись выполнения важна и здесь. «Учётные данные по умолчанию» значит учётные данные записи, которая выполняет этот процесс. Запустите как интерактивного пользователя — аутентификация к прокси как этот пользователь; запустите как службу LocalSystem — как учётная запись компьютера.
- Если прокси аутентифицирует пользователей через Active Directory, он не может аутентифицировать учётную запись компьютера или локальную запись, и 407 продолжается, как только превращаете приложение в службу
- Наоборот, в некоторых средах на стороне прокси есть исключение аутентификации для служб (по исходному IP или по учётной записи)
Поэтому расследование 407 не закрывается одними «настройками приложения»; это комплект с проверкой проектирования на стороне инфраструктуры: может ли прокси аутентифицировать учётную запись выполнения. Для приложения, которое превратите в службу, на этапе проектирования стоит решить одно из: запускать под доменной учётной записью службы (gMSA и подобные), поставить исключение аутентификации на стороне прокси или поднять внутренний релей-прокси без требования аутентификации.
Есть и стиль, который встраивает учётные данные в переменную окружения, как HTTP_PROXY=http://user:pass@proxy:80807, но тогда пароль открытым текстом оказывается в переменной окружения (= сведения о процессе), поэтому для постоянной эксплуатации это не рекомендуется.
7. HTTPS и прокси — туннели CONNECT и TLS-инспекция
7.1. HTTPS проходит через прокси как «туннель»
Когда используете прокси для HTTPS, клиент сначала отправляет прокси запрос CONNECT destination-host:443, и прокси открывает TCP-туннель. При успехе прокси возвращает 200, и после этого клиент и сервер назначения выполняют TLS-рукопожатие внутри этого туннеля. Если туннель не открывается, прокси возвращает 407 (требуется аутентификация), 502 или подобное.16
В этой модели прокси не может читать содержимое туннеля (зашифрованный HTTPS). В журнале прокси остаются имя узла назначения и успех соединения; путь URL не виден — таково поведение прокси «pass-through».
flowchart TB
accTitle: HTTPS через прокси это туннель CONNECT
accDescr: Клиент отправляет CONNECT прокси, прокси открывает TCP-туннель и возвращает 200, затем клиент и назначение выполняют TLS-рукопожатие в туннеле. Журнал прокси видит узел, не путь URL
cli["Клиент"] -->|"CONNECT host:443"| px["Прокси"]
px -->|"200 и TCP-туннель"| dest["Назначение"]
dest -->|"TLS внутри туннеля"| cli
px -.-> log["Журнал: только узел и успех"]
Рис. 7: Прокси pass-through видит узел, не зашифрованный путь.
7.2. Прокси TLS-инспекции и ошибки сертификата
Прокси продуктов безопасности, с другой стороны, включают тип TLS-инспекции (расшифровка SSL, break and inspect), который завершает TLS, проверяет содержимое и заново шифрует перед пересылкой. В этой схеме сертификат сервера, предъявляемый клиенту, не настоящий; он заменяется сертификатом, переподписанным собственной УЦ прокси.13
Посылка, на которой держится эта конфигурация, поэтому такова: «сертификат УЦ прокси раздан в доверенные корневые каждого клиента». На машине, которая его не получила, или в среде выполнения, которая не смотрит хранилище сертификатов Windows (инструменты со своим хранилищем доверия), вы получаете ошибку проверки сертификата. В .NET это обычно проявляется как HttpRequestException, оборачивающий AuthenticationException (сообщение вроде «the remote certificate is invalid»).
Принципы исправления таковы.
- Раздайте внутренний сертификат УЦ в хранилище «Доверенные корневые центры сертификации» локального компьютера. Разделение пользовательского хранилища и хранилища компьютера разобрано в «Практическое руководство по хранилищу сертификатов Windows».
- Не отключайте проверку сертификатов в коде. Обход, который всегда возвращает true из
ServerCertificateCustomValidationCallback, становится уязвимым приложением, которое не может обнаружить «человека посередине», как только выходит во внешнюю сеть. - Трафик с привязкой сертификата нельзя инспектировать изначально. Соединения, которые проверяют конкретный сертификат Microsoft, как делают некоторые компоненты Windows, падают в момент, когда прокси меняет сертификат, и обхода кроме исключения нет.4 Для трафика в сторону SaaS вроде Microsoft 365 сама Microsoft рекомендует исключать его из расшифровки и инспекции на сетевом уровне.13
Симптом «каждый внутренний сайт виден, а только конкретная облачная служба даёт ошибку сертификата в приложении» должен сначала заставить подозревать сочетание списка исключений TLS-инспекции и привязки.
flowchart TB
accTitle: Прокси TLS-инспекции переподписывает сертификат
accDescr: Прокси завершает TLS, проверяет содержимое и предъявляет сертификат, переподписанный собственной УЦ. Проверка держится только если эта УЦ в доверенных корневых. Не отключайте проверку в коде
real["Настоящий сертификат сервера"] --> px["Прокси TLS-инспекции"]
px --> fake["Переподписан УЦ прокси"]
fake --> client["Проверка клиента"]
client -->|"УЦ в доверенных корневых"| ok["Успех"]
client -->|"УЦ нет"| err["Ошибка сертификата"]
err -.-> fix["Раздать УЦ в хранилище"]
Рис. 8: Инспекция работает только в комплекте с раздачей внутренней УЦ.
8. Процедура изоляции — пять шагов, чтобы найти виновника
Расследуйте «не подключается» механически в этом порядке.
| Шаг | Что делаете | Что узнаёте |
|---|---|---|
| (1) Воспроизвести | Обратиться к проблемному URL через curl.exe -v или Invoke-WebRequest (лучше на той же машине, под той же учётной записью) |
Проблема приложения или среды |
| (2) Собрать настройки | Собрать три семейства: netsh winhttp show proxy, пользовательские настройки и переменные окружения |
Что в каком семействе |
| (3) Определить учётную запись | Определить учётную запись выполнения целевого приложения (служба, Планировщик заданий, другой пользователь) | Под какими настройками и какими учётными данными оно работает |
| (4) Классифицировать ошибку | Различить 407 / 403 / сбой разрешения имени / тайм-аут / ошибку сертификата | Изолировать аутентификацию прокси, отказ политики, путь и TLS-инспекцию |
| (5) Журнал прокси | Проверить соответствующее время в журнале доступа прокси-сервера | Достиг ли прокси вообще и кем аутентифицировал |
(2) можно собрать разом через PowerShell.
# (1) Per-user (WinINET) settings — note that this reads HKCU of the running account
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable, ProxyServer, ProxyOverride, AutoConfigURL
# (2) Machine (WinHTTP) settings
netsh winhttp show proxy
# (3) Environment variables
Get-ChildItem env: | Where-Object Name -match 'proxy'
Несколько практических советов.
- В тесте воспроизведения (1) осознавайте, какое семейство настроек читает инструмент. Встроенный
curl.exeWindows может явно указать прокси через-x http://proxy:8080, а для проверки TLS обычно использует хранилище сертификатов ОС (Schannel).Invoke-WebRequestWindows PowerShell 5.1 следует стороне .NET Framework (по умолчанию параметры Интернета); PowerShell 7 следует стороне .NET (сначала переменные окружения). «curl работает, приложение нет» само по себе — намёк на расхождение семейств конфигурации. - Если цель в (3) — служба, перепроверьте (1) и (2) под той же учётной записью, что и служба. Проверка в собственной сессии администратора — не доказательство того, что видит LocalSystem.
- В классификации ошибки (4) берите главу 6 (аутентификация) как первого кандидата для 407, главу 7 (TLS-инспекция) для ошибки сертификата и «не достигает прокси» (путь, разрешение имени, брандмауэр) для тайм-аута. Шаблон, где причина — входящее правило брандмауэра Windows, а не прокси, разобран в «Брандмауэр Windows и деловые приложения».
- Если дошли до (5) и в журнале прокси всё ещё нет следа, трафик никогда не достиг прокси. Подозревайте решение DIRECT у PAC, список обхода или оставшуюся переменную окружения и при необходимости подтвердите фактическое назначение захватом пакетов («Практический захват пакетов в Windows — выбор между pktmon, netsh trace и Wireshark»).
flowchart TB
accTitle: Пять шагов изоляции сбоя прокси
accDescr: Воспроизвести под той же учётной записью, собрать три семейства настроек, определить учётную запись выполнения, классифицировать ошибку, затем проверить журнал прокси
s1["Воспроизвести curl"] --> s2["Собрать три семейства"]
s2 --> s3["Определить учётную запись"]
s3 --> s4["Классифицировать ошибку"]
s4 --> s5["Проверить журнал прокси"]
s4 -.-> e407["407: аутентификация"]
s4 -.-> ecert["Ошибка сертификата: инспекция"]
s4 -.-> eto["Тайм-аут: не достигло"]
Рис. 9: Пройдите пять шагов по порядку. Класс ошибки выбирает следующую главу.
9. Рекомендация по проектированию — сделать приложение таким, на котором можно «настроить прокси»
Переверните процедуру расследования — и получите руководство по проектированию на стороне приложения. Для приложения Windows, которое будете сдавать в среду с корпоративным прокси, рекомендуется следующее.
- Сделайте прокси настраиваемым из настроек приложения. Стандарт — «следовать настройкам ОС». В большинстве сред стандарта достаточно; только в исключительных средах — PAC нельзя прочитать, работает как служба, особая конфигурация прокси — дайте возможность указать URL прокси, список обхода и «не использовать прокси» из файла настроек.
HttpClientHandler.Proxy/UseProxyв разделе 5.3 — точка реализации.14 - Запишите, как внутренние назначения (API, базы данных, серверы лицензий и подобные) обрабатываются как исключения прокси. Положите в форму, которую можно вписать в процедуру развёртывания, исключаются ли они через PAC DIRECT, список обхода или
NO_PROXY. Правила сопоставленияNO_PROXY(без подстановочных знаков, что значит ведущая точка) широко понимают неверно, поэтому приложите примеры.7 - Проектируйте тайм-ауты и повторы в предположении прохождения через прокси. Если прокси лежит или застрял на аутентификации, реализация, которая ждёт длинный стандартный тайм-аут, замораживает и интерфейс, и эксплуатацию. Отделите более короткий тайм-аут соединения и ограничьте повторы идемпотентными запросами (детали проектирования в «Не оборачивайте HttpClient в using»).
- Журналируйте «какой прокси использовался». Сделайте так, чтобы само приложение могло ответить на первый вопрос расследования сбоя.
Журнал как в (4) уже эффективен, если записывает только результат разрешения. Суть — вывести путь из настроек (обработчика), которые вы реально использовали, чтобы настроить клиент. Если журналировать HttpClient.DefaultProxy напрямую, запишете значение, расходящееся с фактическим путём, когда обработчик явно указывает Proxy или ставит UseProxy = false.
using System.Net.Http;
// handler is the same instance used to create the HttpClient
// UseProxy=false is always direct. An explicit specification wins; otherwise DefaultProxy is used
var effectiveProxy = handler.UseProxy
? handler.Proxy ?? HttpClient.DefaultProxy
: null;
var target = new Uri("https://api.example.com/v1/orders");
var route = effectiveProxy is null || effectiveProxy.IsBypassed(target)
? "DIRECT"
: effectiveProxy.GetProxy(target)?.ToString() ?? "DIRECT";
logger.LogInformation("HTTP send {Target} route {Route} account {User}",
target, route, Environment.UserName);
Если при запуске один раз записать «путь» и «учётную запись выполнения» для основных назначений, шаги (1)–(3) главы 8 заканчиваются просто чтением журнала. Когда говорят «в браузере работает, но…», уметь сказать со стороны приложения «я использовал эту настройку и этот путь» — условие приложения, устойчивого к неприятностям прокси.
flowchart TB
accTitle: Сделать прокси настраиваемым и журналировать путь
accDescr: По умолчанию следовать настройкам ОС, разрешить явный URL прокси или обход или отсутствие прокси из настроек приложения и журналировать фактически использованный маршрут вместе с учётной записью выполнения
def["Стандарт: следовать настройкам ОС"] --> exc{"Исключительная среда?"}
exc -->|"PAC не прочитан / служба / особое"| cfg["Задать URL, обход или без прокси"]
exc -->|"Обычный случай"| os["Использовать стандарт ОС"]
cfg --> log["Журналировать маршрут и учётную запись"]
os --> log
Рис. 10: Настраивайте, когда должны. Всегда журналируйте, какой путь использовался.
10. Итог
- Настройки прокси Windows делятся на три семейства — пользовательские настройки WinINET, машинные настройки WinHTTP и переменные окружения — и какое читается, решают приложение (его HTTP-стек) и учётная запись выполнения.
- WinINET — для интерактивных приложений и не поддерживается в службе; служебное использование — работа WinHTTP (
netsh winhttp). Для «вручную работает, как служба нет» сначала подозревайте разницу учётной записи выполнения. netsh winhttp set proxy— статическая настройка и не обрабатывает PAC, автообнаружение и аутентификацию. В сети на PAC нужно решить, как обращаться с клиентами, которые не могут читать PAC.FindProxyForURLPAC возвращает прокси или DIRECT по URL. WPAD работает только в сети с устройством DHCP/DNS.- Стандарт .NET Framework — параметры Интернета учётной записи выполнения (переопределяется
defaultProxy); .NET (Core и новее) — переменные окружения, затем пользовательские настройки прокси. Явное указание (HttpClientHandler.Proxy) всегда наивысший приоритет. - 407 — ошибка аутентификации прокси; в приложении под учётной записью службы типичная причина — «учётные данные по умолчанию» становятся другим лицом.
- Прокси TLS-инспекции предполагает раздачу внутреннего сертификата УЦ, и правильный ответ на ошибку сертификата — раздача в хранилище сертификатов, а не отключение проверки. Трафику с привязкой нужно исключение.
- Изолируйте механически в порядке «воспроизвести → собрать три семейства настроек → определить учётную запись выполнения → классифицировать ошибку → журнал прокси». На стороне приложения проектирование, которое «может настроить прокси и журналирует путь, который использовало», — лучшая профилактика.
В следующий раз, когда вас спросят «только деловое приложение не подключается», сначала задайте это.
Под чьей учётной записью работает это приложение и какое из трёх семейств настроек прокси оно читает?
Один этот вопрос сильно меняет вход в расследование.
Похожие статьи
- Не оборачивайте HttpClient в using ── практика HTTP-взаимодействия в бизнес-приложениях на C# (паттерны создания, тайм-ауты, повторные попытки)
- Практический захват пакетов в Windows — выбор между pktmon, netsh trace и Wireshark
- Брандмауэр Windows и деловые приложения — регистрируйте входящие правила из установщика
- Как создавать и эксплуатировать службы Windows — от выбора между планировщиком заданий и службами до превращения BackgroundService в службу Windows
- NTLM и Kerberos на схемах — почему аутентификация откатывается на NTLM
- Практическое руководство по хранилищу сертификатов Windows — пользователь или компьютер, что выбрать?
Смежные области консультирования
KomuraSoft LLC занимается расследованием сбоев связи приложений Windows в средах корпоративного прокси, аутентифицирующего прокси и TLS-инспекции — «на машине разработки работает, в сети заказчика не общается», «после превращения в службу перестало достигать внешнего API» — и консультациями по проектированию связи деловых приложений, предполагающему среду прокси (пункты настроек, тайм-ауты, проектирование журналов). Можно начать с упорядочивания шагов воспроизведения и способа сбора журналов.
- Разработка приложений для Windows
- Расследование ошибок и причин
- Технические консультации и ревью дизайна
- Связаться с нами
Справочные ссылки
-
Microsoft Learn, WinINet vs. WinHTTP. О руководстве использовать WinINET, если только вы не в службе или процессе, которому нужны олицетворение и изоляция сеанса, и о сравнительной таблице функций, охватывающей кэш учётных данных, запросы учётных данных, поддержку служб, олицетворение, изоляцию сеанса и подобное. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, netsh winhttp. О синтаксисе netsh winhttp show/set/import/reset; proxy-server и bypass-list у set proxy; import proxy source=ie; и подробных настройках прокси в форме JSON (Proxy, ProxyBypass, AutoconfigUrl, AutoDetect) через set advproxy. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, About WinHTTP. О том, что WinHTTP — HTTP-стек, спроектированный для служебного и серверного использования, поддерживающий выполнение под учётной записью службы и олицетворение и не разделяющий cookie, кэш, учётные данные браузера и параметры Интернета пользователя. ↩ ↩2 ↩3
-
Microsoft Learn, Using a proxy with Delivery Optimization. О том, что netsh winhttp set proxy — статическая настройка, не поддерживающая автообнаружение, URL PAC и аутентификацию прокси; о конфигурации прокси на устройство для контекстов без вошедшего пользователя (CSP NetworkProxy, политика «Сделать настройки прокси машинными»); и о трафике с привязкой сертификата, который падает при TLS-инспекции и нуждается в исключении. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Microsoft Learn, WinHTTP AutoProxy Support. О том, что скрипт PAC содержит функцию FindProxyForURL(url, host), которая вычисляет список прокси на запрос и указывает прямое соединение особым возвращаемым значением, и о том, что более старый AutoProxy API не интегрирует автоматически автоматический прокси в HTTP-стек, так что приложение должно вызвать WinHttpGetProxyForUrl. ↩ ↩2 ↩3
-
Microsoft Learn, WinHttpGetProxyForUrl function. О том, что это реализация протокола WPAD, её нужно вызывать по URL, потому что файл PAC может вернуть другой прокси по URL, и она поддерживает и явный URL PAC, и автообнаружение из сети. ↩ ↩2
-
Microsoft Learn, HttpClient.DefaultProxy Property. О том, что Windows сначала читает переменные окружения HTTP_PROXY, HTTPS_PROXY, ALL_PROXY и NO_PROXY и, если они не заданы, пользовательские настройки прокси; что Linux инициализируется без прокси, если переменных окружения нет; что NO_PROXY не поддерживает подстановочные знаки и использует сопоставление поддомена с ведущей точкой; и что URL прокси может включать имя пользователя и пароль. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9
-
Microsoft Learn, Configuring Internet Applications. О том, что элемент defaultProxy определяет прокси по умолчанию в .NET Framework; что HttpWebRequest без свойства Proxy использует прокси по умолчанию; и что системные интернет-настройки и настройки файла конфигурации сочетаются с приоритетом стороны файла конфигурации. ↩ ↩2 ↩3
-
Microsoft Learn, defaultProxy element (network settings). Об атрибутах enabled и useDefaultCredentials элемента system.net/defaultProxy, дочерних элементах proxy, bypasslist и module, о том, что используются системные настройки прокси, если элемент пуст, и о настройке через HttpClient.DefaultProxy при миграции на .NET 6 и новее. ↩ ↩2 ↩3
-
Microsoft Learn, Authentication in WinHTTP. О том, что код состояния 407 и заголовок Proxy-Authenticate возвращаются, когда требуется аутентификация прокси (аутентификация сервера — 401 и WWW-Authenticate); о разнице между аутентификацией Basic и схемами вызов/ответ вроде Kerberos; и о том, что схема вызов/ответ значит, что имя пользователя и пароль не идут по сети. ↩ ↩2 ↩3
-
Microsoft Learn, HttpClientHandler.DefaultProxyCredentials Property. О свойстве, которое задаёт учётные данные, используемые для аутентификации к прокси по умолчанию, когда UseProxy истинно и Proxy равен null, так что используется системный прокси по умолчанию. ↩ ↩2
-
Microsoft Learn, WebProxy.Credentials Property. О том, что свойство Credentials — учётные данные, отправляемые прокси в ответ на HTTP 407, и о рекомендации во многих клиентских сценариях ставить UseDefaultCredentials в true, чтобы использовались учётные данные по умолчанию вошедшего пользователя. ↩ ↩2
-
Microsoft Learn, Understanding implications when using network intermediation to decrypt or manipulate Microsoft 365 traffic at the network layer. О том, что TLS-инспекция (расшифровка SSL) — конфигурация, в которой прокси или брандмауэр расшифровывает, проверяет и заново шифрует TLS; что она может вызвать сбой работы и деградацию производительности в службах, предполагающих сквозной TLS; и о рекомендации исключать трафик в сторону Microsoft 365 из расшифровки и инспекции на сетевом уровне. ↩ ↩2 ↩3
-
Microsoft Learn, Make HTTP requests with the HttpClient class. О двух методах конфигурации HttpClient.DefaultProxy и HttpClientHandler.Proxy; о том, что указание Proxy имеет приоритет над файлом конфигурации и настройками локального компьютера; о типичной конфигурации WPAD получения файла PAC (wpad.dat и подобные) через DNS-имя wpad или DHCP; и о суждении обхода локальных назначений по плоскому имени, петле и совпадению суффикса домена. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, WinHttpOpen function. О значении каждого значения dwAccessType. WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY (Windows 8.1 и новее) автоматически решает прокси из системных/пользовательских настроек прокси и также автоматически обрабатывает отказоустойчивость и аутентификацию, а WINHTTP_ACCESS_TYPE_DEFAULT_PROXY устарел с 8.1. ↩
-
Microsoft Learn, Work with existing on-premises proxy servers. О том, что исходящий HTTPS устанавливается запросом CONNECT к прокси; что успех возвращает HTTP 200; и что ответы вроде 407 (требуется аутентификация) или 502 указывают, что прокси не разрешает связь, поэтому изоляцию стоит продолжать вместе с командой стороны прокси. ↩
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Захват пакетов в Windows на практике — как выбрать между pktmon, netsh trace и Wireshark
Сбой связи, в журнале приложения от которого остаётся только «timeout», расследуют на слой ниже — по пакетам, которые реально прошли по п...
Подводные камни сетевых дисков и UNC-путей ── как бизнес-приложения работают с файловым сервером (общей папкой)
Разбираем типичные проблемы, возникающие при выводе данных и мониторинге общей папки из бизнес-приложения: почему буква диска (Z:) не вид...
Не оборачивайте HttpClient в using ── практика HTTP-взаимодействия в бизнес-приложениях на C# (паттерны создания, тайм-ауты, повторные попытки)
HttpClient в C#, создаваемый через using при каждом запросе, приводит к исчерпанию сокетов, а статический HttpClient перестаёт учитывать ...
Как понимать изоляцию сеансов Windows — Session 0, RDP и одновременная работа нескольких пользователей
В этой статье разбирается понятие «сеанса» (session) в Windows — тема, которая постоянно сбивает с толку разработчиков Windows-приложений...
Защита от повторного запуска приложения Windows — именованный Mutex и активация окна при повторном запуске
Разбираем, как реализовать защиту бизнес-приложения Windows от повторного запуска с помощью именованного Mutex: подводные камни RDP-окруж...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Бизнес-приложения, интеграция оборудования и средства связи — от требований до разработки.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Браузер подключается, а деловое приложение не проходит корпоративный прокси. Почему?
- Браузер читает пользовательские настройки прокси WinINET, но деловое приложение не обязательно читает те же. Приложение, которое работает как служба Windows или под другой учётной записью, смотрит настройки, видимые из этой записи, машинные настройки WinHTTP или переменные окружения. Сначала определите учётную запись выполнения и проверьте настройки прокси, видимые из этой записи, и через netsh winhttp show proxy, и в пользовательских настройках. Если воспроизводите curl.exe или аналогом под той же записью на той же машине, это можно считать расхождением семейств конфигурации, а не проблемой самого приложения.
- Я задал netsh winhttp set proxy, но трафик приложения не изменился. Почему?
- То, что задаёт netsh winhttp, — машинный стандарт WinHTTP. Это не затрагивает браузеры и интерактивные приложения, которые читают WinINET, и HttpClient в .NET (Core и новее), который предпочитает переменные окружения. netsh winhttp set proxy — ещё и статическая настройка; она не обрабатывает автоконфигурацию PAC, автообнаружение и аутентификацию прокси. Сначала нужно подтвердить, какой HTTP-стек использует целевое приложение и из какого семейства конфигурации оно разрешает прокси.
- Какие настройки прокси читает приложение .NET?
- .NET Framework по умолчанию использует параметры Интернета (эквивалент WinINET) учётной записи выполнения, и их можно переопределить элементом system.net/defaultProxy в app.config. HttpClient в .NET (Core и новее) сначала читает переменные окружения HTTP_PROXY, HTTPS_PROXY и NO_PROXY и, если они не заданы, падает на пользовательские настройки прокси Windows. В обоих случаях явный HttpClientHandler.Proxy имеет приоритет. Порядок разрешения по умолчанию поэтому различается между Framework и Core и новее, так что при миграции нужно заново проверить поведение прокси.
- Что проверять, когда возвращается 407 Proxy Authentication Required?
- 407 — признак того, что сам прокси требует аутентификации; это иное, чем ошибка аутентификации сервера назначения (401). Сначала подтвердите схему, которую просит прокси (Negotiate, NTLM, Basic), по заголовку Proxy-Authenticate, а в .NET передайте учётные данные через HttpClientHandler.DefaultProxyCredentials или WebProxy.UseDefaultCredentials. В приложении под учётной записью службы «учётные данные по умолчанию» становятся данными этой службы, поэтому типичный инцидент: у интерактивного пользователя работает, а как только превращаете в службу — 407. Проверьте также в журнале прокси, кем он аутентифицировал.
- Прокси TLS-инспекции даёт ошибки сертификата. Можно ли отключить проверку сертификатов?
- Отключать не рекомендуется. Прокси TLS-инспекции расшифровывает трафик и затем предъявляет клиенту сертификат, переподписанный собственной УЦ, поэтому проверка падает, если этот сертификат УЦ не в доверенных корневых. Правильное исправление — раздать внутренний сертификат УЦ в хранилище сертификатов Windows (обычно «Доверенные корневые центры сертификации» локального компьютера). Отключение проверки в коде значит, что атаку «человек посередине» нельзя обнаружить, когда приложение используют во внешней сети, и уязвимость остаётся.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.