사내 프록시와 Windows 앱 ── WinINET, WinHTTP, .NET의 프록시 해석을 정리한다

· · Windows, Proxy, WinHTTP, WinINET, .NET, HttpClient, PAC, WPAD, 네트워크

「브라우저는 외부 사이트를 여는데, 업무 앱만 외부 API에 닿지 못한다.」 「개발 머신에서는 되는데, 고객 네트워크에서는 타임아웃이다.」 「손으로 실행하면 통신하고, Windows 서비스로 바꾸는 순간 실패한다.」 ── 사내 프록시가 있는 환경에서 업무 앱을 돌리면, 이런 상담이 가장 흔합니다.

대부분의 경우 원인은 프록시 서버 장애도, 앱 버그도 아닙니다. Windows에는 「프록시 설정」이라고 부르는 계열이 여러 개 따로 있고, 누가 어떤 설정을 읽는지는 앱(그것이 쓰는 HTTP 스택)과 실행 계정에 따라 다르다 ── 그 불일치입니다. 브라우저가 읽는 설정, 서비스가 읽는 설정, .NET HttpClient가 읽는 설정은 각각 다른 것일 수 있습니다. 그 구조가 머릿속에 들어가면, 「브라우저에서는 되는데…」의 격리가 의외로 빨라집니다.

이 글은 중소기업 IT 담당자와 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마다 바뀝니다. PAC 파일의 FindProxyForURL 함수는 URL과 호스트를 받아 프록시 목록 또는 직접 연결(DIRECT)을 반환합니다. 「저 사이트는 되는데 이 API만 안 된다」는 PAC 분기일 수 있습니다.56
  • .NET(Core 이후)의 HttpClient는 기본 프록시를 환경 변수 → Windows 사용자 프록시 설정 순으로 초기화합니다. HTTP_PROXY, HTTPS_PROXY, ALL_PROXY 중 하나라도 정의되어 있으면 OS 설정보다 우선하므로, 「누가 환경 변수를 남겨 두었다」는 사고가 납니다.7
  • .NET Framework의 기본은 실행 계정의 인터넷 옵션이며, app.config의 defaultProxy로 덮어쓸 수 있습니다. 구성 파일 설정이 시스템 설정보다 우선합니다.89
  • 407은 프록시 인증 오류이며, 401(서버 인증)과는 다른 일입니다. 스킴에는 Negotiate, NTLM, Basic이 있고, .NET에서는 DefaultProxyCredentials 또는 WebProxy.UseDefaultCredentials로 자격 증명을 넘깁니다. 서비스 계정에서는 「기본 자격 증명」의 내용이 바뀐다는 점을 보십시오.101112
  • TLS 검사 프록시는 내부 CA 인증서 배포와 세트로만 성립합니다. 받지 못한 컴퓨터와 런타임은 인증서 유효성 검사 오류가 납니다. 앱에서 유효성 검사를 끄는 것이 아니라, 인증서 저장소에 배포해서 해결하십시오.134

한 문장으로: 「프록시 설정을 확인했다」고 말할 때마다, 세 계열 중 어느 것을, 어느 계정에서 확인했는지 말할 수 있어야 한다 ── 그것이 이 글의 주제입니다.

2. Windows에는 「프록시 설정」이 세 계열 있다

먼저 전체 지도입니다. Windows 앱이 사내 프록시를 찾는 경로는 이 세 계열로 떨어집니다.

설정 계열 설정 위치 / 명령 범위 주로 읽는 것
(1) WinINET(인터넷 옵션) 설정 → 네트워크 및 인터넷 → 프록시, inetcpl.cpl 사용자별(기본) 브라우저, 대화형 데스크톱 앱, .NET Framework 기본
(2) WinHTTP(컴퓨터 설정) netsh winhttp set proxy / set advproxy 컴퓨터 Windows 서비스, 일부 OS 구성 요소
(3) 환경 변수 HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY 프로세스(정의한 곳에 따라 상속) .NET(Core 이후) HttpClient, 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)을 읽습니다. 그래서 보통 「프록시 설정은 맞는데 그래도 연결되지 않는다」가 아니라, 현실은 「앱이 읽는 계열이 확인한 계열과 다른 계열이었다」입니다.

Windows 프록시 설정의 세 계열WinINET은 사용자별 설정과 인터넷 옵션, WinHTTP는 netsh의 컴퓨터 기본값, 환경 변수는 프로세스 범위이다. 어느 계열을 읽을지는 설정 쪽이 아니라 앱이 결정한다어느 계열인가?WinINET 사용자별 설정WinHTTP 컴퓨터 설정HTTP_PROXY와 그 친구들브라우저와 데스크톱 앱서비스와 일부 OS 부분.NET Core+와 curl

그림 1: 세 계열이 나란히 있다. 앱이 어느 것을 읽을지 고른다.

그룹 정책 「프록시 설정을 사용자별이 아니라 컴퓨터별로 만들기」를 켜면 (1)을 컴퓨터별로 바꿔 모든 사용자에게 같은 설정을 적용할 수 있습니다. MDM(Intune 등)에서는 NetworkProxy CSP로 장치별로 구성할 수 있습니다.4

3. WinINET과 WinHTTP ── 대화형 앱용과 서비스용

3.1. 역할의 차이

WinINET과 WinHTTP는 둘 다 Windows 기본 제공 HTTP 클라이언트 스택이지만, 가정하는 용도가 다릅니다.

  • WinINET: 대화형 데스크톱 앱을 겨냥합니다. 사용자의 인터넷 옵션(프록시, 쿠키, 자격 증명 캐시)을 자동으로 이어받고, 필요하면 자격 증명 입력 UI까지 띄울 수 있습니다. 서비스나 서비스와 비슷한 프로세스에서의 사용은 지원되지 않습니다.1
  • WinHTTP: 서비스와 서버 쪽을 겨냥합니다. 서비스 계정에서의 실행, 스레드 가장, 세션 격리를 지원하는 대신, 사용자의 브라우저 설정·쿠키·자격 증명을 공유하지 않습니다. UI도 띄우지 않습니다.3

Microsoft 자신의 안내도 마찬가지로 분명합니다. 「서비스 안에서, 또는 세션 격리와 가장이 필요한 서비스와 비슷한 프로세스에서 돌지 않는 한 WinINET을 쓰라」 ── 뒤집으면 서비스라면 WinHTTP를 쓰라입니다.1

대화형 앱은 WinINET, 서비스는 WinHTTPWinINET은 로그온한 사용자의 인터넷 옵션을 이어받으며 서비스에서는 지원되지 않는다. WinHTTP는 UI 없이 서비스 계정으로 돌며 사용자의 브라우저 설정을 공유하지 않는다서비스 또는 그와 비슷함대화형 데스크톱 앱인가?WinINETWinHTTP사용자의 인터넷 옵션을 읽음컴퓨터 설정, 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

여기서 기억할 제약 두 가지입니다.

  1. netsh winhttp set proxy는 정적 설정입니다. 프록시 자동 검색도, PAC URL 지정도, 프록시 인증도 다루지 않습니다.4
  2. import proxy source=ie는 그 순간의 정적 설정만 복사하며, 이후 인터넷 옵션 쪽 변경을 따라가지 않습니다. PAC나 자동 검색을 포함하는 컴퓨터 단위 구성이 필요하면, JSON 형식의 상세 설정(Proxy, ProxyBypass, AutoconfigUrl, AutoDetect)을 netsh winhttp set advproxy로 구성하십시오.2

3.3. 가장 흔한 함정: 서비스는 사용자의 IE 설정을 읽지 않는다

현장에서 가장 자주 보는 패턴을 시간 순으로 쓰면 이렇습니다.

  1. 개발자가 자기 PC에서 도구를 실행 → 사용자별 프록시 설정 (1)이 적용되어 된다
  2. 프로덕션에서는 LocalSystem 아래 Windows 서비스(Windows 서비스 만드는 방법과 운영)로 상주시킨다
  3. LocalSystem에서 보이는 설정은 다른 것(사용자별 설정은 보이지 않고, WinHTTP 컴퓨터 설정은 미구성 = DIRECT) → 외부 API에 직접 연결을 시도하고 타임아웃

「같은 컴퓨터인데도 안 된다」가 아니라, 같은 컴퓨터라도 실행 계정이 다르면 보이는 프록시 설정 집합이 다릅니다. 사용자가 로그온하지 않아도 통신하는 프로세스에는, 그 프로세스의 HTTP 스택이 실제로 읽는 형태로 컴퓨터 단위 설정을 준비하는 것이 올바른 접근입니다. WinHTTP를 쓰는 네이티브 앱이나 Windows 구성 요소에는 netsh WinHTTP 설정이 적용됩니다.4 반면 .NET(Core 이후)의 HttpClient는 WinHTTP의 컴퓨터 설정을 읽지 않으므로(5장 참조), .NET 서비스에는 시스템 환경 변수(HTTPS_PROXY 등)를 두거나 앱 설정에서 HttpClientHandler.Proxy를 명시적으로 지정합니다.

반대 방향의 사고도 납니다. 사내 네트워크와 외부를 오가는 노트북에 netsh winhttp set proxy로 정적 프록시를 구워 넣으면, 회사 밖에서는 그 프록시에 닿지 못해 통신이 완전히 죽습니다. 컴퓨터 정적 설정은 네트워크 구성이 바뀌지 않는 서버를 겨냥한 수단으로 다루십시오.4

서비스가 사용자의 IE 설정을 보지 못하는 이유개발자 실행은 사용자별 WinINET 설정을 읽어 된다. LocalSystem에서는 그 설정이 보이지 않는다. 네이티브 WinHTTP 앱은 미구성 컴퓨터 설정(DIRECT)을 따른다. .NET Core+ 서비스는 여전히 환경 변수나 명시적 handler.Proxy를 쓰며 netsh winhttp로 바뀌지 않는다WinHTTP.NET Core+사용자로 손으로 실행WinINET 사용자별 설정이 적용LocalSystem Windows 서비스사용자별 설정이 보이지 않음어느 HTTP 스택인가?WinHTTP 미구성 = DIRECT환경 변수 또는 handler.Proxy외부 API가 타임아웃

그림 3: 같은 컴퓨터, 다른 계정, 보이는 프록시 설정 집합이 다르다.

4. PAC와 WPAD ── 「자동 구성」의 실제

4.1. PAC 파일과 FindProxyForURL

PAC(Proxy Auto-Configuration) 파일은 「이 URL에 어떤 프록시를 쓸지」를 계산하는 JavaScript(ECMAScript)이며, 항상 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를 통한 자동 검색

「설정 자동 검색」을 켜면 머신은 WPAD(Web Proxy Auto-Discovery) 프로토콜로 PAC 파일의 위치를 찾습니다. 전형적인 구성에서는 DHCP가 PAC URL을 건네거나, DNS로 wpad라는 호스트를 찾아 http://wpad/wpad.dat 같은 URL에서 PAC를 내려받습니다.14

즉 「자동 검색」은 마법이 아니라, DHCP/DNS에 이미 WPAD 장치가 있는 네트워크에서만 동작하는 메커니즘입니다. 그런 장치가 없는 네트워크에서 자동 검색만 켜면 검색 실패를 기다리는 시간만 늘어납니다.

PAC는 URL마다 프록시를 정하고, WPAD는 PAC만 찾는다FindProxyForURL은 URL과 호스트를 받아 프록시 목록 또는 DIRECT를 반환한다. WPAD는 DHCP 또는 DNS로 PAC 위치만 찾는다. PAC를 평가하지 못하는 클라이언트는 정적 프록시 또는 환경 변수로 폴백한다프록시 목록DIRECT요청 URLFindProxyForURL프록시를 통과프록시 없이 연결DHCP 또는 DNS의 WPADPAC를 평가하지 못하는 클라이언트정적 설정 또는 환경 변수

그림 4: PAC는 URL마다 결정한다. WPAD는 PAC 파일만 찾는다.

4.3. PAC를 평가하지 못하는 클라이언트의 동작

모든 클라이언트가 PAC를 평가할 수 있는 것은 아닙니다.

  • netsh winhttp set proxy의 정적 설정은 PAC를 평가하지 않습니다.4
  • HTTP_PROXY 환경 변수 스타일을 쓰는 도구는 원칙적으로 고정 프록시 URL만 쓸 수 있습니다(PAC URL을 쓸 곳이 없습니다).7
  • WinHTTP를 직접 쓰는 네이티브 앱은 세션을 연 방식에 달립니다. Windows 8.1 이후 WinHttpOpen에서 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 이후)에서 기본이 다릅니다. 둘을 섞으면 Framework 시대 지식으로 .NET 8 앱을 조사하다 놓칩니다.

5.1. .NET Framework ── 기본은 인터넷 옵션, defaultProxy로 덮어씀

.NET Framework에서 HttpWebRequest와 그 위에 앉은 HttpClientProxy를 명시하지 않으면 기본 프록시를 씁니다. 기본 프록시는 시스템의 인터넷 설정(실행 계정의 WinINET 설정)과 구성 파일의 조합으로 결정되며, 구성 파일 설정이 우선합니다.8

이 기본값은 app.config(또는 machine.config)의 system.net/defaultProxy 요소로 제어할 수 있습니다.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 이후) ── 환경 변수가 먼저, 그다음 OS 사용자 설정

.NET(Core 이후)의 HttpClient에는 정적 속성 HttpClient.DefaultProxy가 있습니다. 핸들러가 프록시를 명시하지 않으면 모든 HttpClient 인스턴스가 그것을 씁니다. Windows에서의 초기화 규칙은 「환경 변수를 읽고, 정의되어 있지 않으면 사용자 프록시 설정을 읽는다」입니다.7

쓰이는 환경 변수는 다음과 같습니다.7

환경 변수 의미
HTTP_PROXY HTTP 요청에 쓰는 프록시
HTTPS_PROXY HTTPS 요청에 쓰는 프록시
ALL_PROXY 위가 정의되지 않았을 때의 폴백
NO_PROXY 프록시를 쓰지 말아야 할 호스트의 쉼표 구분 목록

주의할 점 세 가지입니다.

  • HTTP_PROXY, HTTPS_PROXY, ALL_PROXY 중 하나라도 정의되어 있으면 OS 쪽 프록시 설정보다 우선합니다. NO_PROXY만 정의하는 것은 환경 변수로 프록시를 구성하는 것이 아니며, Windows에서는 OS 사용자 프록시 설정이 계속 쓰입니다. 옛 실험 뒤 HTTPS_PROXY를 시스템 환경 변수로 남겨 두거나, CI/CD 템플릿이 주입하는 같은 「보이지 않는 설정」이 사고의 온상입니다.
  • NO_PROXY는 와일드카드(*)를 지원하지 않습니다. 서브도메인을 맞추려면 앞쪽 점(.example.comwww.example.com에는 맞지만 example.com 자체에는 맞지 않음)을 둡니다.7
  • Windows가 아닌 곳(Linux 컨테이너 등)에서는 환경 변수가 정의되어 있지 않으면 프록시 없이 초기화됩니다. 같은 앱의 기본 동작이 Windows와 Linux에서 바뀌는 것은 컨테이너 마이그레이션 때 확인할 일입니다.7

5.3. 명시적 지정 ── HttpClientHandler.Proxy와 UseProxy

어느 런타임이든 최우선은 핸들러의 명시적 지정입니다. HttpClientHandler.Proxy를 지정하면 OS 설정과 구성 파일보다 우선하고, 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);

명시적 지정이 없고 OS 설정을 따를 때, 로컬 대상의 자동 바이패스에는 규칙이 있습니다. 점이 없는 평면 이름, 루프백 주소, 머신의 자체 도메인 접미사에 맞는 대상 등은 「로컬」로 취급될 수 있습니다.14 「IP 주소를 지정하면 동작이 바뀐다」거나 「FQDN을 쓰니 갑자기 프록시를 타기 시작했다」는 현상은 이 판단이 원인일 수 있습니다.

우선순위는 다음과 같습니다.

우선순위(높음 → 낮음) .NET Framework .NET(Core 이후)
1 HttpClientHandler.Proxy 같은 명시적 지정 동일
2 app.config의 defaultProxy HttpClient.DefaultProxy에 대한 대입
3 실행 계정의 인터넷 옵션 환경 변수(HTTP_PROXY 등)
4 Windows 사용자 프록시 설정
Framework와 Core 이후의 기본 프록시 해석명시적 HttpClientHandler.Proxy는 항상 이긴다. Framework는 그다음 app.config defaultProxy와 실행 계정의 인터넷 옵션을 쓴다. Core 이후는 HttpClient.DefaultProxy 대입, 그다음 환경 변수, 그다음 Windows 사용자 프록시 설정FrameworkCore 이후명시적 handler.Proxy그 프록시를 사용명시적 Proxy 없음어느 런타임인가?app.config defaultProxy실행 계정 인터넷 옵션HttpClient.DefaultProxyHTTP_PROXY와 그 친구들Windows 사용자 프록시 설정

그림 5: 명시적 지정은 항상 이긴다. 기본 경로는 런타임마다 다르다.

6. 인증 프록시 ── 407은 프록시의 인증 오류

6.1. 407과 401을 혼동하지 말 것

인증을 요구하는 프록시를 통과하려 하면, 프록시는 상태 코드 407(Proxy Authentication Required)과 사용 가능한 스킴을 나열한 Proxy-Authenticate 헤더를 반환합니다. 그것은 대상 서버의 인증 요구(401과 WWW-Authenticate)와는 다른 일이며, 자격 증명을 건네는 상대와 구성하는 곳도 둘 다 다릅니다.10

407은 프록시, 401은 대상 서버407과 Proxy-Authenticate는 프록시에서 온다. 401과 WWW-Authenticate는 대상 서버에서 온다. 자격 증명과 구성하는 곳이 다르다프록시대상아웃바운드 요청누가 인증을 요구하는가?407 + Proxy-Authenticate401 + WWW-AuthenticateDefaultProxyCredentials

그림 6: 407은 프록시 인증이다. 401은 서버 인증이다.

스킴에는 사용자 이름과 비밀번호를 그대로 보내는 Basic과, Negotiate(Kerberos/NTLM) 같은 챌린지/응답 스킴이 있습니다. 챌린지/응답 스킴에서는 비밀번호 자체가 네트워크를 타지 않으며, 인증은 여러 왕복으로 끝납니다.10 어느 스킴으로 「폴백」하는 메커니즘은 「그림으로 이해하는 NTLM과 Kerberos」에서 더 자세히 다룹니다.

6.2. .NET에서 자격 증명을 넘기는 방법

OS 설정에서 온 기본 프록시를 쓰면서 인증만 통과시키고 싶을 때는 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:8080처럼 환경 변수에 자격 증명을 넣는 스타일도 있지만7, 그러면 평문 비밀번호가 환경 변수(= 프로세스 정보)에 노출되므로 상시 운영에는 권장하지 않습니다.

7. HTTPS와 프록시 ── CONNECT 터널과 TLS 검사

7.1. HTTPS는 프록시를 「터널」로 통과한다

HTTPS에 프록시를 쓸 때, 클라이언트는 먼저 프록시에 CONNECT destination-host:443 요청을 보내고, 프록시가 TCP 터널을 엽니다. 성공하면 프록시는 200을 반환하고, 그 뒤 클라이언트와 대상 서버는 그 터널 안에서 TLS 핸드셰이크를 수행합니다. 터널이 열리지 않으면 프록시는 407(인증 필요), 502 등을 반환합니다.16

이 모델에서 프록시는 터널의 내용(암호화된 HTTPS)을 읽을 수 없습니다. 프록시 로그에 남는 것은 대상 호스트 이름과 연결 성공 여부이며, URL 경로는 보이지 않습니다 ── 그것이 「패스스루」 프록시의 동작입니다.

프록시를 통한 HTTPS는 CONNECT 터널이다클라이언트가 프록시에 CONNECT를 보내고, 프록시가 TCP 터널을 열어 200을 반환한 뒤, 클라이언트와 대상이 터널 안에서 TLS 핸드셰이크를 한다. 프록시 로그는 호스트는 보고 URL 경로는 보지 않는다CONNECT host:443200과 TCP 터널터널 안의 TLS클라이언트프록시대상로그: 호스트와 성공만

그림 7: 패스스루 프록시는 호스트는 보고, 암호화된 경로는 보지 않는다.

7.2. TLS 검사 프록시와 인증서 오류

반면 보안 제품 프록시에는 TLS를 종료하고 내용을 검사한 뒤 다시 암호화해 전달하는 TLS 검사(SSL 복호화, break and inspect) 유형이 있습니다. 이 방식에서 클라이언트에 제시되는 서버 인증서는 진짜가 아니라, 프록시 자체 CA로 재서명한 인증서로 교체됩니다.13

그래서 이 구성이 성립하는 전제는 「프록시의 CA 인증서가 모든 클라이언트의 신뢰된 루트에 배포되어 있다」입니다. 받지 못한 컴퓨터, 또는 Windows 인증서 저장소를 보지 않는 런타임(자체 신뢰 저장소를 가진 도구)에서는 인증서 유효성 검사 오류가 납니다. .NET에서는 보통 AuthenticationException을 감싼 HttpRequestException(「원격 인증서가 유효하지 않다」류의 메시지)으로 표면에 나옵니다.

수정의 원칙은 다음과 같습니다.

  • 내부 CA 인증서를 로컬 컴퓨터의 「신뢰할 수 있는 루트 인증 기관」 저장소에 배포하십시오. 사용자 저장소와 컴퓨터 저장소의 분기는 「Windows 인증서 저장소 실무 가이드」에서 다룹니다.
  • 코드에서 인증서 유효성 검사를 끄지 마십시오. ServerCertificateCustomValidationCallback에서 항상 true를 반환하는 우회는, 외부 네트워크에 나가는 순간 중간자를 감지하지 못하는 취약한 앱이 됩니다.
  • 인증서 고정(pinning) 트래픽은 원래 검사할 수 없습니다. 일부 Windows 구성 요소처럼 특정 Microsoft 인증서를 검증하는 연결은, 프록시가 인증서를 바꾸는 순간 실패하며, 제외 외에는 우회가 없습니다.4 Microsoft 365 같은 SaaS로 가는 트래픽에 대해 Microsoft 자신은 네트워크 계층 복호화와 검사에서 제외할 것을 권장합니다.13

「모든 내부 사이트는 보이는데, 특정 클라우드 서비스만 앱에서 인증서 오류가 난다」는 증상은 먼저 TLS 검사 제외 목록과 고정의 조합을 의심해야 합니다.

TLS 검사 프록시는 인증서를 재서명한다프록시가 TLS를 종료하고 내용을 검사한 뒤 자체 CA로 재서명한 인증서를 제시한다. 유효성 검사는 그 CA가 신뢰된 루트에 있을 때만 성립한다. 코드에서 유효성 검사를 끄지 말 것CA가 신뢰된 루트에CA 없음진짜 서버 인증서TLS 검사 프록시프록시 CA로 재서명클라이언트 유효성 검사성공인증서 오류CA를 저장소에 배포

그림 8: 검사는 내부 CA 배포와 세트로만 동작한다.

8. 격리 절차 ── 범인을 찾는 다섯 단계

「연결되지 않음」을 이 순서로 기계적으로 조사하십시오.

단계 하는 일 알게 되는 것
(1) 재현 curl.exe -v 또는 Invoke-WebRequest로 문제 URL에 접근(가능하면 같은 컴퓨터, 같은 계정) 앱 고유 문제인지 환경 문제인지
(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)의 재현 테스트에서는 도구가 어느 설정 계열을 읽는지 의식하십시오. Windows 기본 제공 curl.exe-x http://proxy:8080으로 프록시를 명시할 수 있고, TLS 유효성 검사에는 보통 OS 인증서 저장소(Schannel)를 씁니다. Windows PowerShell 5.1의 Invoke-WebRequest는 .NET Framework 쪽(기본은 인터넷 옵션)을 따르고, PowerShell 7은 .NET 쪽(환경 변수 우선)을 따릅니다. 「curl은 되는데 앱은 안 된다」 자체가 설정 계열 간 불일치의 힌트입니다.
  • (3)의 대상이 서비스이면, 서비스와 같은 계정에서 (1)과 (2)를 다시 확인하십시오. 관리자 자신의 세션에서의 확인은 LocalSystem이 보는 것의 증거가 아닙니다.
  • (4)의 오류 분류에서는 407의 첫 후보로 6장(인증), 인증서 오류에는 7장(TLS 검사), 타임아웃에는 「프록시에 닿지 않았다」(경로, 이름 확인, 방화벽)를 잡으십시오. 원인이 프록시가 아니라 Windows 방화벽 인바운드 규칙인 패턴은 「Windows 방화벽과 업무 앱」에서 다룹니다.
  • (5)까지 가서도 프록시 로그에 흔적이 없으면, 트래픽이 프록시에 닿지 않은 것입니다. PAC의 DIRECT 결정, 바이패스 목록, 남은 환경 변수를 의심하고, 필요하면 패킷 캡처로 실제 대상을 확인하십시오(「Windows의 패킷 캡처 실무 ── pktmon, netsh trace, Wireshark의 선택」).
프록시 장애를 격리하는 다섯 단계같은 계정에서 재현하고, 세 계열의 설정을 수집하고, 실행 계정을 식별하고, 오류를 분류한 뒤 프록시 로그를 확인한다curl로 재현세 계열 수집계정 식별오류 분류프록시 로그 확인407: 인증인증서 오류: 검사타임아웃: 도달하지 않음

그림 9: 다섯 단계를 순서대로 걷는다. 오류 클래스가 다음 장을 고른다.

9. 설계 권장 ── 앱을 「프록시를 구성할 수 있는」 것으로 만들기

조사 절차를 뒤집으면 앱 쪽 설계 지침이 됩니다. 사내 프록시가 있는 환경에 납품할 Windows 앱에는 다음을 권장합니다.

  1. 앱 설정에서 프록시를 구성할 수 있게 하십시오. 기본은 「OS 설정을 따른다」입니다. 대부분의 환경에서는 기본으로 충분하고, PAC를 읽지 못하거나 서비스로 돌거나 특수 프록시 구성인 예외 환경에서만 설정 파일에서 프록시 URL, 바이패스 목록, 「프록시를 쓰지 않음」을 지정할 수 있게 합니다. 5.3절의 HttpClientHandler.Proxy / UseProxy가 구현 지점입니다.14
  2. 내부 대상(API, 데이터베이스, 라이선스 서버 등)을 프록시 예외로 다루는 방법을 적어 두십시오. PAC DIRECT, 바이패스 목록, NO_PROXY 중 무엇으로 제외하는지를 배포 절차에 쓸 수 있는 형태로 두십시오. NO_PROXY 매칭 규칙(와일드카드 없음, 앞쪽 점의 의미)은 널리 오해되므로 예를 붙이십시오.7
  3. 타임아웃과 재시도를 프록시 통과를 가정하고 설계하십시오. 프록시가 죽거나 인증에 막히면, 긴 기본 타임아웃을 기다리는 구현은 UI와 운영을 둘 다 얼립니다. 더 짧은 연결 타임아웃을 분리하고, 재시도는 멱등 요청으로 제한하십시오(설계 세부는 「HttpClient를 using으로 감싸면 안 되는 이유」).
  4. 「어느 프록시를 썼는지」를 로그하십시오. 장애 조사의 첫 질문에 앱 스스로 답할 수 있게 하십시오.

(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);

시작 시 주요 대상에 대해 「경로」와 「실행 계정」을 한 번 기록해 두면, 8장의 (1)부터 (3)까지는 로그만 읽으면 끝납니다. 「브라우저에서는 되는데…」라는 말을 들을 때, 앱 쪽에서 「이 설정을 썼고, 이 경로였다」고 말할 수 있는 것이 프록시 사고에 강한 앱의 조건입니다.

프록시를 구성할 수 있게 하고 경로를 로그한다기본은 OS 설정을 따르고, 예외 환경에서는 앱 설정에서 명시적 프록시 URL이나 바이패스 또는 프록시 없음을 허용하며, 실제로 쓴 경로를 실행 계정과 함께 로그한다PAC 미평가 / 서비스 / 특수보통의 경우기본: OS 설정을 따름예외 환경인가?URL, 바이패스, 또는 프록시 없음OS 기본값 사용경로와 계정을 로그

그림 10: 필요할 때 구성한다. 어느 경로를 썼는지는 항상 로그한다.

10. 정리

  • Windows 프록시 설정은 WinINET 사용자별 설정, WinHTTP 컴퓨터 설정, 환경 변수 세 계열로 나뉘고, 어느 것을 읽을지는 앱(그 HTTP 스택)과 실행 계정이 결정합니다.
  • WinINET은 대화형 앱용이며 서비스에서의 사용은 지원되지 않고, 서비스 용도는 WinHTTP(netsh winhttp)의 일입니다. 「손으로 하면 되고 서비스로는 안 된다」에는 먼저 실행 계정 차이를 의심하십시오.
  • netsh winhttp set proxy는 정적 설정이며 PAC, 자동 검색, 인증을 다루지 않습니다. PAC로 운영하는 네트워크에서는 PAC를 읽지 못하는 클라이언트를 어떻게 다룰지 정해야 합니다.
  • PAC의 FindProxyForURL은 URL마다 프록시 또는 DIRECT를 반환합니다. WPAD는 DHCP/DNS 장치가 있는 네트워크에서만 동작합니다.
  • .NET Framework의 기본은 실행 계정의 인터넷 옵션(defaultProxy로 덮어쓸 수 있음)이고, .NET(Core 이후)은 환경 변수 다음에 사용자 프록시 설정입니다. 명시적 지정(HttpClientHandler.Proxy)이 항상 최우선입니다.
  • 407은 프록시 인증 오류이며, 서비스 계정으로 도는 앱에서 전형적인 원인은 「기본 자격 증명」이 다른 사람이 되는 것입니다.
  • TLS 검사 프록시는 내부 CA 인증서 배포를 전제로 하며, 인증서 오류에 대한 올바른 답은 유효성 검사를 끄는 것이 아니라 인증서 저장소에 배포하는 것입니다. 고정된 트래픽에는 제외가 필요합니다.
  • 「재현 → 세 계열의 설정 수집 → 실행 계정 식별 → 오류 분류 → 프록시 로그」 순으로 기계적으로 격리하십시오. 앱 쪽에서는 「프록시를 구성할 수 있고, 쓴 경로를 로그하는」 설계가 최고의 예방입니다.

다음에 「업무 앱만 연결되지 않는다」는 상담을 받으면, 먼저 이것을 물으십시오.

그 앱은 누구의 계정으로 돌고, 프록시 설정의 세 계열 중 어느 것을 읽는가?

그 한 질문이 조사의 입구를 크게 바꿉니다.

관련 기사

관련 상담 영역

합동회사 코무라소프트는 사내 프록시·인증 프록시·TLS 검사 환경에서 Windows 앱 통신 장애 조사 ── 「개발 머신에서는 되는데 고객 네트워크에서는 통신하지 못한다」, 「서비스로 바꾼 뒤 외부 API에 닿지 못하게 되었다」 ── 와 프록시 환경을 전제로 한 업무 앱 통신 설계(설정 항목, 타임아웃, 로그 설계) 상담을 다룹니다. 재현 절차와 로그 수집 방법을 정리하는 단계부터여도 괜찮습니다.

참고 링크

  1. Microsoft Learn, WinINet vs. WinHTTP. 서비스이거나 가장과 세션 격리가 필요한 프로세스가 아니면 WinINET을 쓰라는 안내, 그리고 자격 증명 캐시, 자격 증명 프롬프트, 서비스 지원, 가장, 세션 격리 등을 다루는 기능 비교표에 대해.  2 3 4

  2. Microsoft Learn, netsh winhttp. netsh winhttp show/set/import/reset의 구문, set proxy의 proxy-server와 bypass-list, import proxy source=ie, set advproxy를 통한 JSON 형식의 상세 프록시 설정(Proxy, ProxyBypass, AutoconfigUrl, AutoDetect)에 대해.  2 3 4

  3. Microsoft Learn, About WinHTTP. WinHTTP가 서비스·서버 쪽 용도로 설계된 HTTP 스택이며 서비스 계정에서의 실행과 가장을 지원하고, 브라우저의 쿠키·캐시·자격 증명이나 사용자의 인터넷 옵션을 공유하지 않는다는 점에 대해.  2 3

  4. Microsoft Learn, Using a proxy with Delivery Optimization. netsh winhttp set proxy가 자동 검색·PAC URL·프록시 인증을 지원하지 않는 정적 설정이라는 점, 로그온 사용자가 없는 컨텍스트를 위한 장치별 프록시 구성(NetworkProxy CSP, 「프록시 설정을 컴퓨터별로 만들기」 정책), TLS 검사에서 인증서 고정 트래픽이 실패하므로 제외가 필요하다는 점에 대해.  2 3 4 5 6 7 8 9 10

  5. Microsoft Learn, WinHTTP AutoProxy Support. PAC 스크립트가 요청마다 프록시 목록을 계산하는 FindProxyForURL(url, host) 함수를 포함하고 특수 반환값으로 직접 연결을 나타낸다는 점, 오래된 AutoProxy API는 자동 프록시를 HTTP 스택에 자동 통합하지 않아 앱이 WinHttpGetProxyForUrl을 호출해야 한다는 점에 대해.  2 3

  6. Microsoft Learn, WinHttpGetProxyForUrl function. WPAD 프로토콜의 구현이며 PAC 파일이 URL마다 다른 프록시를 반환할 수 있어 URL마다 호출해야 한다는 점, 명시적 PAC URL과 네트워크에서의 자동 검색을 모두 지원한다는 점에 대해.  2

  7. 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

  8. Microsoft Learn, Configuring Internet Applications. .NET Framework에서 defaultProxy 요소가 기본 프록시를 정의한다는 점, Proxy 속성이 없는 HttpWebRequest가 기본 프록시를 쓴다는 점, 시스템 인터넷 설정과 구성 파일 설정이 결합되며 구성 파일 쪽이 우선한다는 점에 대해.  2 3

  9. Microsoft Learn, defaultProxy element (network settings). system.net/defaultProxy 요소의 enabled와 useDefaultCredentials 특성, proxy·bypasslist·module 자식 요소, 요소가 비어 있으면 시스템 프록시 설정이 쓰인다는 점, .NET 6 이후로 마이그레이션할 때 HttpClient.DefaultProxy로 구성한다는 점에 대해.  2 3

  10. Microsoft Learn, Authentication in WinHTTP. 프록시 인증이 필요할 때 상태 코드 407과 Proxy-Authenticate 헤더가 반환된다는 점(서버 인증은 401과 WWW-Authenticate), Basic 인증과 Kerberos 같은 챌린지/응답 스킴의 차이, 챌린지/응답 스킴에서는 사용자 이름과 비밀번호가 네트워크를 타지 않는다는 점에 대해.  2 3

  11. Microsoft Learn, HttpClientHandler.DefaultProxyCredentials Property. UseProxy가 true이고 Proxy가 null이어서 시스템 기본 프록시를 쓸 때, 그 기본 프록시에 대한 인증에 쓰는 자격 증명을 설정하는 속성에 대해.  2

  12. Microsoft Learn, WebProxy.Credentials Property. Credentials 속성이 HTTP 407에 대한 응답으로 프록시에 보내는 자격 증명이라는 점, 많은 클라이언트 시나리오에서 UseDefaultCredentials를 true로 두어 로그온한 사용자의 기본 자격 증명을 쓰라는 권장에 대해.  2

  13. 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

  14. Microsoft Learn, Make HTTP requests with the HttpClient class. HttpClient.DefaultProxy와 HttpClientHandler.Proxy의 두 구성 방법, Proxy 지정이 구성 파일과 로컬 컴퓨터 설정보다 우선한다는 점, DNS 이름 wpad 또는 DHCP로 PAC 파일(wpad.dat 등)을 얻는 전형적인 WPAD 구성, 평면 이름·루프백·도메인 접미사 일치에 의한 로컬 대상 바이패스 판단에 대해.  2 3 4

  15. Microsoft Learn, WinHttpOpen function. 각 dwAccessType 값의 의미. WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY(Windows 8.1 이후)가 시스템/사용자 프록시 설정에서 프록시를 자동 결정하고 장애 조치와 인증도 자동으로 다루며, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY는 8.1부터 사용 중단된다는 점에 대해. 

  16. Microsoft Learn, Work with existing on-premises proxy servers. 아웃바운드 HTTPS가 프록시에 대한 CONNECT 요청으로 수립된다는 점, 성공 시 HTTP 200이 반환된다는 점, 407(인증 필요)이나 502 같은 응답은 프록시가 통신을 허용하지 않았다는 뜻이므로 프록시 쪽 팀과 격리를 진행해야 한다는 점에 대해. 

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

브라우저는 연결되는데 업무 앱만 사내 프록시를 넘지 못합니다. 왜인가요?
브라우저는 WinINET의 사용자별 프록시 설정을 읽지만, 업무 앱이 반드시 같은 설정을 읽는 것은 아닙니다. Windows 서비스로 돌거나 다른 계정으로 도는 앱은 그 계정에서 보이는 설정, WinHTTP의 컴퓨터 설정, 또는 환경 변수를 참조합니다. 먼저 실행 계정을 확인하고, 그 계정에서 보이는 프록시 설정을 netsh winhttp show proxy와 사용자 설정 양쪽에서 점검하십시오. 같은 컴퓨터의 같은 계정에서 curl.exe 등으로 재현되면, 앱 고유 문제가 아니라 설정 계열 간의 불일치로 보면 됩니다.
netsh winhttp set proxy를 설정했는데 앱 트래픽이 변하지 않습니다. 왜인가요?
netsh winhttp가 설정하는 것은 WinHTTP의 컴퓨터 기본값입니다. WinINET을 읽는 브라우저나 대화형 앱, 환경 변수를 우선하는 .NET(Core 이후) HttpClient에는 영향을 주지 않습니다. netsh winhttp set proxy는 정적 설정이며 PAC 자동 구성, 자동 검색, 프록시 인증을 다루지 않습니다. 대상 앱이 어떤 HTTP 스택을 쓰는지, 어느 설정 계열에서 프록시를 해석하는지부터 확인해야 합니다.
.NET 앱은 어떤 프록시 설정을 읽나요?
.NET Framework는 기본적으로 실행 계정의 인터넷 옵션(WinINET 상당) 설정을 쓰고, app.config의 system.net/defaultProxy 요소로 덮어쓸 수 있습니다. .NET(Core 이후)의 HttpClient는 HTTP_PROXY, HTTPS_PROXY, NO_PROXY 같은 환경 변수를 먼저 읽고, 정의되어 있지 않으면 Windows 사용자 프록시 설정으로 넘어갑니다. 어느 쪽이든 명시적인 HttpClientHandler.Proxy가 우선합니다. 기본 해석 순서가 Framework와 Core 이후에서 다르므로, 마이그레이션 때는 프록시 동작을 다시 확인해야 합니다.
407 Proxy Authentication Required가 반환되면 무엇을 확인해야 하나요?
407은 프록시 자체가 인증을 요구한다는 신호이며, 대상 서버 인증 오류(401)와는 다른 일입니다. 먼저 Proxy-Authenticate 헤더로 프록시가 요구하는 인증 스킴(Negotiate, NTLM, Basic)을 확인하고, .NET에서는 HttpClientHandler.DefaultProxyCredentials 또는 WebProxy.UseDefaultCredentials로 자격 증명을 넘깁니다. 서비스 계정으로 도는 앱에서는 「기본 자격 증명」이 그 서비스 계정의 것이 되므로, 대화형 사용자에서는 되고 서비스로 바꾸는 순간 407이 나는 전형적인 사고가 납니다. 프록시 쪽 로그에서 누구로 인증했는지도 확인하십시오.
TLS 검사 프록시에서 인증서 오류가 납니다. 인증서 유효성 검사를 꺼도 되나요?
끄는 것은 권장하지 않습니다. TLS 검사 프록시는 트래픽을 복호화한 뒤 클라이언트에 자체 CA로 재서명한 인증서를 제시하므로, 그 CA 인증서가 신뢰된 루트에 없으면 유효성 검사가 실패합니다. 올바른 수정은 내부 CA 인증서를 Windows 인증서 저장소(보통 로컬 컴퓨터의 신뢰할 수 있는 루트 인증 기관)에 배포하는 것입니다. 코드에서 유효성 검사를 끄면 앱을 외부 네트워크에서 쓸 때 중간자 공격을 감지하지 못하고, 취약점이 남습니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기