更新履歴(7件・最終更新 2026年09月07日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- プロキシ設定の参照先と実行アカウントの違いという主張を維持し、症状別の案内、設定の優先順位、PAC・認証・TLSの説明と5ステップの調査手順を図付きで整理した。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの「.NETのDefaultProxyはプロキシ環境変数を必要とする」という関係を、「プロキシ環境変数で構成される(未定義ならユーザー設定へフォールバック)」に改めました。本文の説明は変えていません。
- 知識マップの「TLSインスペクション型プロキシはCONNECTトンネルと両立しない」という関係を、「CONNECT要求を受けたうえでTLSを終端して中身を復号する(利用する)」に改めました。本文の説明は変えていません。
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.22054255)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「社内プロキシとWindowsアプリ ── WinINET・WinHTTP・.NETのプロキシ解決を整理する」合同会社小村ソフト. https://doi.org/10.5281/zenodo.22054255 https://comcomponent.com/blog/windows-proxy-wininet-winhttp-dotnet/
- DOI(最新版)
- 10.5281/zenodo.22054255
- DOI(この版)
- 10.5281/zenodo.22556480
「ブラウザーでは外部サイトを開けるのに、業務アプリだけ外部APIにつながらない」「手動実行では動くのに、Windowsサービスにした途端に失敗する」。社内プロキシのある環境では、こうした食い違いがよく起こります。
調査の出発点は、そのアプリが、誰のアカウントで、どのプロキシ設定を読んでいるかです。Windowsのプロキシ設定は1つではありません。ブラウザー、サービス、.NETのHttpClientが、それぞれ別の設定を参照していることがあります。
原因の大半は、プロキシサーバーの障害やアプリのバグではなく、この設定系統と実行アカウントの食い違いです。この記事では、中小企業の情シス担当者とWindowsアプリ開発者に向けて、設定の全体像から、PAC・認証・証明書、切り分け手順へと順に整理します。
| 困っていること・知りたいこと | 最初に読む箇所 |
|---|---|
| ブラウザーだけ通信できる/設定したのに挙動が変わらない | 3系統の設定 |
| 手動実行では動くが、サービスにすると失敗する | 実行アカウントの違い |
| 特定のURLだけ通らない/PACの設定が使われない | PACとWPAD |
| .NET Frameworkから.NETへ移したら挙動が変わった | .NETの解決順序 |
| 407が返る | プロキシ認証 |
| 証明書エラーが出る | TLSインスペクション |
| 何から調べるか分からない | 5ステップの切り分け |
HttpClientの生成パターンやタイムアウト設計そのものは「HttpClientをusingで囲んではいけない」で扱います。本記事の中心は、どの設定からプロキシを解決し、その後のどこで通信が止まるかです。
1. まず結論
最初に押さえたいのは、次の3点です。
- 設定を見る前に、アプリと実行アカウントを特定する。WinINETのユーザー別設定、WinHTTPのマシン設定、環境変数のうち、どれを読むかはアプリ側で決まります。管理者の画面で見た設定が、サービスからも見えるとは限りません。123
- 通信できるURLではなく、問題のURLで調べる。PACはURLごとにプロキシやDIRECTを返します。.NETでも、ランタイムの違いや環境変数、ハンドラーの明示指定で経路が変わります。456
- 経路・認証・証明書を分けて調べる。407はプロキシ認証で、接続先の401とは別です。TLSインスペクションの証明書エラーは、検証を無効化するのではなく、社内CAの配布や必要な除外設定で対処します。783
flowchart TB
accTitle: プロキシ調査で揃える情報
accDescr: アプリのHTTPスタックと実行アカウントを特定し、そのアカウントから見える設定と問題のURLを揃えて、経路と認証と証明書を調べる
app["HTTPスタックとアカウント"] --> settings["そのアカウントの設定を確認"]
settings --> url["問題のURLで経路を確認"]
url --> error["認証と証明書も分けて調べる"]
図1: 「どの設定か」「誰から見た設定か」「どのURLか」を揃えてから、失敗している場所を調べる。
一文でまとめるなら、「プロキシ設定を確認した」と言うとき、3系統のどれを、どのアカウントから見たのかを言えるようにすることです。
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全19件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. Windowsには「プロキシ設定」が3系統ある
Windows上のアプリが社内プロキシを見つける経路は、大きく3系統に分かれます。
| 設定系統 | 設定場所・コマンド | スコープ | 主に読むもの |
|---|---|---|---|
| ① WinINET(インターネットオプション) | 設定アプリ→ネットワークとインターネット→プロキシ、inetcpl.cpl |
ユーザー別(既定) | ブラウザー、対話型デスクトップアプリ、.NET Frameworkの既定 |
| ② WinHTTP(マシン設定) | netsh winhttp set proxy / set advproxy |
マシン | Windowsサービス、OSコンポーネントの一部 |
| ③ 環境変数 | HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY |
プロセス(定義元により継承) | .NET(Core以降)のHttpClient、curl、Node.js・Python等のクロスプラットフォーム系ツール |
「Windowsのプロキシ設定」は、通常は①を指す
設定アプリで見えている「プロキシ」は、歴史的にはInternet Explorerのインターネットオプションであり、WinINETの構成です。既定ではユーザーごとに保存されます。3
②は、サービスなど「サインインしたユーザーがいない文脈」のためのマシン単位の既定です。③は主にクロスプラットフォーム由来のツールの流儀で、Windowsでも.NET(Core以降)やcurlなどが読みます。5
どれを読むかは、設定した人ではなくアプリが決める
WinINETを使うアプリなら①、WinHTTPなら②またはアプリ独自の指定、.NET(Core以降)なら③→①というように、参照先が決まっています。
したがって、「設定は正しいのにつながらない」ときは、確認した設定と、アプリが読んだ設定が同じ系統かを先に確かめます。3系統すべてを同じ値にして回る前に、対象アプリの入口を特定することが重要です。
ユーザー単位ではなく、デバイス単位にする構成もある
グループポリシー「プロキシの設定をユーザーごとではなくコンピューターごとに設定する」を有効にすると、①をマシン単位へ切り替えて全ユーザーに同じ設定を適用できます。MDM(Intune等)ならNetworkProxy CSPでデバイス単位に構成できます。3
flowchart TB
accTitle: ユーザー別設定の適用範囲を変える
accDescr: WinINETの設定は既定ではユーザー別だが、グループポリシーでコンピューターごとの設定に切り替えられ、MDMではNetworkProxy CSPでデバイス単位に構成できる
user["WinINET設定は既定でユーザー別"] --> gp["GPOでコンピューター単位へ"]
gp --> all["全ユーザーに同じ設定を適用"]
mdm["MDMのNetworkProxy CSP"] --> device["デバイス単位に構成"]
図2: ①の設定範囲をデバイス単位に変える構成もあるため、「ユーザー別」は既定の状態として読む。
3. WinINETとWinHTTP ── 対話型アプリ用とサービス用
3.1. 役割の違い
WinINETとWinHTTPは、どちらもWindows標準のHTTPクライアントスタックです。ただし、想定する実行形態が異なります。
WinINETは対話型デスクトップアプリ向けです。ユーザーのインターネットオプション、プロキシ、Cookie、資格情報キャッシュを自動的に引き継ぎ、必要なら資格情報の入力UIも出せます。一方、サービスやサービス的なプロセスでの利用はサポートされません。1
WinHTTPはサービス・サーバーサイド向けです。サービスアカウントでの実行、スレッドの偽装(impersonation)、セッション分離をサポートします。その代わり、ブラウザーの設定・Cookie・資格情報は共有せず、UIも出しません。2
Microsoftの使い分けの指針も、サービス内やセッション分離・偽装を必要とするサービス的プロセスでなければWinINET、サービスならWinHTTPです。1 ただし、サービスとして動くアプリがすべてWinHTTPのマシン設定を読む、という意味ではありません。.NET製サービスの扱いは3.3節で分けます。
3.2. netsh winhttpの基本操作
WinHTTPのマシン既定プロキシは、netshで操作します。9
:: 現在のWinHTTPプロキシ設定を表示
netsh winhttp show proxy
:: 静的プロキシを設定(バイパスリスト付き)
netsh winhttp set proxy proxy-server="proxy.example.co.jp:8080" bypass-list="*.example.co.jp;<local>"
:: インターネットオプション(WinINET)の設定を取り込む
netsh winhttp import proxy source=ie
:: 既定(DIRECT)へ戻す
netsh winhttp reset proxy
静的設定・取り込み・自動構成を混同しない
set proxyは静的設定です。自動検出、PAC URLの指定、プロキシ認証は扱いません。3
import proxy source=ieは、実行した時点の静的設定を写す操作です。その後インターネットオプションを変更しても、WinHTTP側は追従しません。
flowchart TB
accTitle: プロキシ設定の取り込みは一度のコピー
accDescr: import proxy source=ieはその時点の静的設定をWinHTTPへコピーするだけで、後からインターネットオプションを変更しても自動追従しない
source["実行時点の静的設定"] --> copy["import proxy source=ie"]
copy --> dest["WinHTTPへコピー"]
source -.-> later["後日の変更は自動追従しない"]
図3: importは同期の設定ではなく、その時点の静的設定を取り込む操作。
PACやWPADによる自動検出を含めてマシン単位に構成する場合は、netsh winhttp set advproxyを使います。JSON形式の詳細設定には、Proxy・ProxyBypass・AutoconfigUrl・AutoDetectがあります。9
3.3. 最頻出の落とし穴: サービスはユーザーのIE設定を読まない
典型例は、開発者が自分のPCで動かしていたツールを、LocalSystemのWindowsサービスへ移すケースです。
開発中は自分のユーザー別設定(①)で通信できていても、LocalSystemから見える設定は別物です。WinHTTPのマシン設定が未構成(DIRECT)なら、外部APIへ直結しようとしてタイムアウトします。サービス化そのものの手順は「Windowsサービスの作り方と運用」で扱っています。
flowchart TB
accTitle: 手動実行からサービス化したときの食い違い
accDescr: 開発者のユーザー別設定で動いていたツールをLocalSystemのサービスにすると見える設定が変わり、WinHTTPの既定がDIRECTなら直結を試みて失敗する
dev["開発者として手動実行"] --> works["自分の設定で通信できる"]
works --> service["LocalSystemのサービスへ変更"]
service --> changed["見える設定が変わる"]
changed --> direct["WinHTTP未構成なら直結"]
direct --> failure["外部APIでタイムアウト"]
図4: マシンが同じでも、実行アカウントが変わると参照できる設定が変わる。
設定は、そのHTTPスタックが読む形で用意する
ユーザーがサインインしていなくても通信するプロセスには、マシン単位の設定を用意します。ただし、設定方法はHTTPスタックに合わせます。
| 対象 | 設定の用意のしかた |
|---|---|
| WinHTTPを使うネイティブアプリ・Windowsコンポーネント | netshのWinHTTP設定を用意する3 |
| .NET(Core以降)のHttpClientを使うサービス | システム環境変数(HTTPS_PROXY等)、またはアプリ設定からHttpClientHandler.Proxyを明示指定する |
.NET(Core以降)のHttpClientはWinHTTPのマシン設定を読みません。「サービスだからnetshを設定すればよい」とは判断しないでください。詳しい優先順位は5章で確認します。
持ち出しPCへの静的設定は、逆方向の事故も招く
ラップトップに社内の静的プロキシを固定すると、社外ではそのプロキシに到達できず、通信できなくなります。マシン静的設定は、ネットワーク構成が変わらないサーバー向きの手段と考えます。3
4. PACとWPAD ── 「自動構成」の中身
PACは経路を計算するもの、WPADはPACの場所を探すものです。「自動構成」をこの2つに分けると、どこを確認すべきかが見えます。
4.1. PACファイルとFindProxyForURL
PAC(Proxy Auto-Configuration)はJavaScript(ECMAScript)で書くファイルです。必須のFindProxyForURL(url, host)関数が、指定されたURLとホストについて、使うプロキシのリストか、直接接続を示すDIRECTを返します。10
function FindProxyForURL(url, host) {
// 社内ドメインとプライベートアドレスは直結
if (dnsDomainIs(host, ".example.co.jp") ||
isInNet(host, "10.0.0.0", "255.0.0.0")) {
return "DIRECT";
}
// それ以外はプロキシ経由。先頭が使えなければ次へフォールバック
return "PROXY proxy1.example.co.jp:8080; PROXY proxy2.example.co.jp:8080; DIRECT";
}
この例では、社内ドメインと指定したプライベートアドレスは直結、それ以外はプロキシ経由です。後者は、先頭のプロキシが使えなければ次へ進み、最後にDIRECTへフォールバックします。
flowchart TB
accTitle: PACは宛先によって経路を変える
accDescr: 記載したPACの例ではURLとホストを判定し、社内ドメインや指定したプライベートアドレスならDIRECT、それ以外ならプロキシの順序付きリストを返す
target["URLとホストを渡す"] --> check{"例の社内宛条件に一致?"}
check -->|"はい"| direct["DIRECTを返す"]
check -->|"いいえ"| proxies["プロキシ1・2・DIRECTの順"]
図5: PACの答えはURLごとに変わるため、別のサイトの成功では問題のAPIの経路を確かめられない。
ここから、調査上の注意が2つ出ます。
問題のURLを渡して確認する。PACはURLごとに別の答えを返し得ます。WinHTTPの自動プロキシ機能も、リクエスト対象のURLを渡して都度問い合わせる設計です。「ブラウザーで別のサイトは見える」は、問題のAPIが同じ経路を通る証明ではありません。4
プロキシログにない通信は、DIRECTやバイパスも疑う。DIRECTは「プロキシを使わずに行け」という指示です。社内宛の通信がログに出ない場合は、PACのDIRECT判定やバイパスリストとの一致を確認します。
4.2. WPADによる自動検出
「設定を自動的に検出する」をオンにすると、WPAD(Web Proxy Auto-Discovery)でPACファイルの場所を探します。一般的にはDHCPでPAC URLを配るか、DNSでwpadというホストを引き、http://wpad/wpad.datのようなURLから取得します。11
flowchart TB
accTitle: 自動検出からPAC取得まで
accDescr: WPADではDHCPまたはDNSでPACファイルの場所を探し、その場所からPACを取得して経路の計算に使う
auto["自動検出を有効にする"] --> find["DHCPまたはDNSで場所を探す"]
find --> pac["PACファイルを取得"]
pac --> route["宛先ごとの経路を計算"]
find -.-> missing["仕掛けがなければ検出に失敗"]
図6: 自動検出には、ネットワーク側のDHCP/DNSによる仕掛けが必要。
仕掛けのないネットワークで自動検出だけをオンにしても機能せず、検出失敗までの待ち時間が増えます。「自動」を選べばどこでも解決するわけではありません。
4.3. PACを読めないクライアントの挙動
PACを配布していても、すべてのクライアントが評価するとは限りません。netsh winhttp set proxyは静的設定であり、環境変数HTTP_PROXY方式のツールにも、原則としてPAC URLを書く場所はありません。固定のプロキシURLを指定します。35
WinHTTPを直接使うネイティブアプリでは、セッションの開き方を確認します。
| WinHttpOpenの使い方 | 自動プロキシの扱い |
|---|---|
Windows 8.1以降でWINHTTP_ACCESS_TYPE_AUTOMATIC_PROXYを指定 |
システム/ユーザーの設定(WPAD/PACを含む)から、WinHTTPがリクエストごとに自動解決する12 |
従来のWINHTTP_ACCESS_TYPE_DEFAULT_PROXYなどを指定 |
アプリ自身がWinHttpGetProxyForUrlを呼び、結果をリクエストへ設定する必要がある。DEFAULT_PROXYは8.1以降では非推奨1012 |
flowchart TB
accTitle: WinHTTPでPACが使われるかを確認する
accDescr: WinHTTPのセッションがAUTOMATIC_PROXYで開かれていれば自動解決されるが、従来の開き方ではアプリ側がAutoProxy APIを呼んで結果を設定する必要がある
open["WinHttpOpenの指定を確認"] --> mode{"AUTOMATIC_PROXY?"}
mode -->|"はい"| automatic["WinHTTPが自動解決"]
mode -->|"従来の開き方"| api["アプリがAutoProxy APIを呼ぶ"]
api --> apply["結果をリクエストへ設定"]
図7: WinHTTPを使っているという情報だけで、PACも自動的に使われるとは判断できない。
古い実装では、PACがあっても使われないことがあります。PAC運用のネットワークでは、PACを読めないクライアントに静的設定や環境変数で何を渡すかも決めておきます。
5. .NETのプロキシ解決 ── FrameworkとCore以降で別物
.NET Frameworkと.NET(Core以降)では、既定プロキシの決まり方が違います。Framework時代の知識で.NET 8のアプリを調べると、確認する設定を間違えることがあります。
5.1. .NET Framework ── 既定はインターネットオプション、defaultProxyで上書き
.NET FrameworkのHttpWebRequestや、その上に乗るHttpClientは、Proxyを明示しない限り既定プロキシを使います。これは実行中アカウントのインターネット設定(WinINET相当)と構成ファイルの組み合わせで決まり、構成ファイルの設定が優先されます。6
app.configまたはmachine.configのsystem.net/defaultProxyで制御します。13
<configuration>
<system.net>
<!-- useDefaultCredentials: 認証プロキシへ既定資格情報を送るか -->
<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で同じ既定を差し替えられます。136
flowchart TB
accTitle: .NET Frameworkの既定プロキシ
accDescr: .NET Frameworkでは実行中アカウントのインターネット設定を基にし、構成ファイルで指定した値を優先して既定プロキシを決める
account["実行アカウントの設定"] --> config["構成ファイルの指定を優先"]
config --> default["Frameworkの既定プロキシ"]
replace["DefaultWebProxyで差し替え"] -.-> default
図8: Frameworkの既定は「実行中アカウント」の設定であり、管理者の画面で見える設定とは限らない。
サービスアカウントで動かす場合は、3.3節と同じ注意が必要です。既定で読むのはそのアカウントのインターネットオプションで、管理者のデスクトップで見えるものとは別の、たいてい空の設定です。
5.2. .NET(Core以降) ── 環境変数が先、次にOSのユーザー設定
.NET(Core以降)には静的プロパティHttpClient.DefaultProxyがあります。ハンドラーで明示指定しない場合に使う既定で、Windowsでは環境変数を読み、定義されていなければユーザーのプロキシ設定を読む順で初期化されます。5
| 環境変数 | 意味 |
|---|---|
HTTP_PROXY |
HTTPリクエストに使うプロキシ |
HTTPS_PROXY |
HTTPSリクエストに使うプロキシ |
ALL_PROXY |
上記が未定義のときのフォールバック |
NO_PROXY |
プロキシを使わないホストのカンマ区切りリスト |
プロキシを指定する3変数と、NO_PROXYを分ける
HTTP_PROXY・HTTPS_PROXY・ALL_PROXYのいずれかが定義されていると、OS側の設定より優先されます。検証用のHTTPS_PROXYが残っていたり、CI/CDのテンプレートが注入していたりすると、画面で見た設定とは違う経路になります。
一方、NO_PROXYだけを定義しても、環境変数によるプロキシは構成されません。Windowsでは引き続きOSのユーザープロキシ設定が使われます。
flowchart TB
accTitle: Windows上の.NETの既定プロキシ初期化
accDescr: HTTP_PROXYとHTTPS_PROXYとALL_PROXYのいずれかが定義されていれば環境変数を優先し、定義されていなければWindowsのユーザー設定を使う。NO_PROXYだけでは環境変数によるプロキシは構成されない
init["既定プロキシの初期化"] --> env{"プロキシ指定の3変数あり?"}
env -->|"はい"| useenv["環境変数を優先"]
env -->|"いいえ"| user["Windowsのユーザー設定"]
init -.-> no["NO_PROXYだけでは構成しない"]
図9: 環境変数によるプロキシ指定があるかを先に確認し、NO_PROXYだけの状態とは区別する。
NO_PROXYの「先頭のドット」とLinuxでの違い
NO_PROXYはワイルドカード(*)をサポートしません。先頭にドットを付けた.example.comはwww.example.comには一致しますが、example.com自体には一致しません。5
Linuxコンテナー等では、環境変数が未定義ならプロキシなしで初期化されます。WindowsとLinuxでは既定挙動が変わるため、コンテナーへ移すときも確認します。5
5.3. 明示指定 ── HttpClientHandler.ProxyとUseProxy
どちらのランタイムでも、HttpClientHandler.Proxyへの明示指定が最優先です。OS設定や構成ファイルより優先されます。UseProxy = falseならプロキシを一切使いません。11
using System.Net;
// アプリ設定から読んだプロキシを明示的に使う
var handler = new HttpClientHandler
{
Proxy = new WebProxy("http://proxy.example.co.jp:8080")
{
BypassProxyOnLocal = true,
BypassList = new[] { @"^intra\.example\.co\.jp$" },
UseDefaultCredentials = true // 認証プロキシなら実行アカウントの資格情報で応答
},
UseProxy = true
};
var client = new HttpClient(handler);
// プロキシを一切使わないクライアント(社内API直結用)
var directHandler = new HttpClientHandler { UseProxy = false };
var directClient = new HttpClient(directHandler);
flowchart TB
accTitle: ハンドラーから有効なプロキシを決める
accDescr: UseProxyがfalseなら直結し、trueならハンドラーのProxyへの明示指定を使い、明示指定がなければ既定プロキシを使う
use{"UseProxyはtrue?"} -->|"いいえ"| direct["直結"]
use -->|"はい"| explicit{"Proxyを明示指定?"}
explicit -->|"はい"| proxy["指定したプロキシを使う"]
explicit -->|"いいえ"| default["既定プロキシを使う"]
図10: 既定プロキシを調べる前に、ハンドラーでの明示指定とUseProxyを確認する。
ローカル宛の自動バイパスにも注意する
明示指定がなくOS設定に従う場合、ドットを含まないフラット名、ループバックアドレス、自マシンのドメインサフィックスと一致する宛先などは、「ローカル」とみなされてバイパスされ得ます。11
「IPアドレス直指定と名前指定で挙動が違う」「FQDNにしたらプロキシを通り始めた」ときは、この判定を確認します。
ここまでの優先順位をまとめると、次のとおりです。
| 優先順位(高→低) | .NET Framework | .NET(Core以降) |
|---|---|---|
| 1 | HttpClientHandler.Proxy等の明示指定 |
同左 |
| 2 | app.configのdefaultProxy |
HttpClient.DefaultProxyへの代入 |
| 3 | 実行アカウントのインターネットオプション | 環境変数(HTTP_PROXY等) |
| 4 | ― | Windowsのユーザープロキシ設定 |
6. 認証プロキシ ── 407は「プロキシの」認証エラー
6.1. 407と401を混同しない
プロキシに到達しても、認証を通れなければ先へ進めません。認証の要求元は、ステータスコードとヘッダーで分けます。7
| 応答 | 認証を要求する相手 | 確認するヘッダー |
|---|---|---|
| 407 Proxy Authentication Required | プロキシ | Proxy-Authenticate |
| 401 | 接続先サーバー | WWW-Authenticate |
407では、まずProxy-Authenticateに列挙された方式を確認します。Basicはユーザー名とパスワードを送る方式、Negotiate(Kerberos/NTLM)などはチャレンジ/レスポンス方式です。後者ではパスワード自体は流れず、複数回のやり取りで認証が完了します。7
sequenceDiagram
accTitle: 認証プロキシへの応答の流れ
accDescr: クライアントがプロキシから407と認証方式の通知を受け、その方式に応じた資格情報で応答する。チャレンジレスポンス方式では複数回のやり取りが必要になる
participant C as クライアント
participant P as プロキシ
C->>P: 通信を要求
P-->>C: 407とProxy-Authenticate
C->>P: 方式に応じて認証に応答
Note over C,P: 方式により複数回やり取りする
図11: 407では接続先サーバーではなく、プロキシへ送る認証情報を確認する。
どの認証方式に「落ちる」かは「図解でわかるNTLMとKerberos」で詳しく扱っています。
6.2. .NETでの資格情報の渡し方
既定プロキシに従う場合と、プロキシを明示する場合で、設定する場所が違います。
既定プロキシを使い、認証情報を渡す場合はHttpClientHandler.DefaultProxyCredentialsを使います。これはUseProxy = trueかつProxy = nullのときに、その既定プロキシへ送る資格情報です。14
using System.Net;
var handler = new HttpClientHandler
{
UseProxy = true, // 既定値。null Proxyと組み合わせるとシステム既定のプロキシを使う
Proxy = null,
// 実行アカウント(サインイン中ユーザーまたはサービスアカウント)の資格情報で407に応答
DefaultProxyCredentials = CredentialCache.DefaultCredentials
};
var client = new HttpClient(handler);
プロキシを明示指定する場合は、WebProxy側に資格情報を持たせます。多くのクライアントシナリオでは個別のユーザー名・パスワードではなく、サインイン中ユーザーの既定資格情報を使うのが推奨で、WebProxy.UseDefaultCredentials = trueがそれに当たります。15
6.3. サービスアカウントの407問題
「既定の資格情報」は、そのプロセスを動かすアカウントの資格情報です。対話ユーザーならそのユーザー、LocalSystemのサービスならコンピューターアカウントとして認証されます。
flowchart TB
accTitle: サービス化で認証される主体が変わる
accDescr: 既定資格情報を使う場合、対話実行ではそのユーザー、LocalSystemのサービスではコンピューターアカウントとして認証されるため、プロキシがその主体を認証できるか確認する
run{"実行アカウントは?"} -->|"対話ユーザー"| user["そのユーザーの資格情報"]
run -->|"LocalSystem"| machine["コンピューターアカウント"]
user --> check["プロキシが認証できるか確認"]
machine --> check
図12: コードで「既定」を選んだままでも、サービス化するとプロキシが認証する主体は変わる。
AD連携でユーザー認証するプロキシでは、コンピューターアカウントやローカルアカウントを認証できず、407が続くことがあります。逆に、送信元IPやアカウント単位でサービス用の認証除外を設けている環境もあります。
そのため、サービス化するアプリでは、ドメインのサービスアカウント(gMSA等)を使うか、プロキシ側で認証除外を設けるか、認証不要の内部中継プロキシを用意するかを、設計段階で決めます。407の調査は、アプリの設定と「その実行アカウントをプロキシが認証できるか」の両方が必要です。
HTTP_PROXY=http://user:pass@proxy:8080のように環境変数へ資格情報を埋め込む方法もあります。5 ただし平文パスワードが環境変数、つまりプロセス情報に露出するため、恒久運用には推奨しません。
7. HTTPSとプロキシ ── CONNECTトンネルとTLSインスペクション
7.1. HTTPSはプロキシを「トンネル」で通る
HTTPSでプロキシを使う場合は、まずクライアントがCONNECT 宛先ホスト:443を送り、TCPトンネルを開通させます。成功時はプロキシが200を返し、その後にクライアントと宛先サーバーがトンネル内でTLSハンドシェイクを行います。開通しない場合には407や502などが返ります。16
flowchart TB
accTitle: HTTPSのトンネルが開通するまで
accDescr: HTTPSではCONNECT要求でTCPトンネルを開き、200が返った後にトンネル内でTLSハンドシェイクを行う。トンネルが開通しない場合は407や502などが返る
connect["CONNECTで宛先を指定"] --> result{"トンネル開通?"}
result -->|"成功・200"| tls["トンネル内でTLS接続"]
result -->|"失敗"| error["407や502など"]
図13: トンネルを開く段階の失敗と、その後のTLS接続の失敗を分けて読む。
この「素通し型」では、プロキシは暗号化されたHTTPSの中身を読めません。ログに見えるのは宛先ホスト名と接続の成否までで、URLパスは見えません。
7.2. TLSインスペクション型プロキシと証明書エラー
TLSインスペクション(SSL復号、break and inspect)型では、プロキシがTLSをいったん終端し、復号・検査してから再暗号化します。クライアントへ提示される証明書も、プロキシ自身のCAで署名し直したものに置き換わります。8
flowchart TB
accTitle: TLSインスペクションで証明書が変わる
accDescr: TLSインスペクションではプロキシがTLSを終端して内容を検査し、クライアントには自分のCAで署名し直した証明書を提示するため、そのCAへの信頼が必要になる
proxy["プロキシがTLSを終端"] --> inspect["復号・検査・再暗号化"]
proxy --> cert["社内CAで再署名した証明書"]
cert --> trust["クライアント側のCA信頼が必要"]
図14: インスペクション型では、接続先の証明書だけでなく社内CAを信頼できるかが問題になる。
まず、どの信頼ストアで検証しているかを確認する
この構成には、プロキシのCA証明書が全クライアントの信頼されたルートへ配布されていることが必要です。未配布のマシンだけでなく、独自の信頼ストアを使ってWindowsの証明書ストアを見ないランタイムでも、証明書検証エラーになります。
.NETでは、典型的にはHttpRequestExceptionと、その内部のAuthenticationExceptionとして現れます。「リモート証明書が無効」といったメッセージを確認します。
対処はCAの配布。検証の無効化ではない
社内CA証明書は、通常、ローカルコンピューターの「信頼されたルート証明機関」へ配布します。ユーザーストアとの使い分けは「Windows証明書ストア実務ガイド」を参照してください。
ServerCertificateCustomValidationCallbackで常にtrueを返すような回避は行いません。社外ネットワークで使われたときも、中間者攻撃を検出できない脆弱性として残ります。
ピン留めされた通信は、インスペクションから除外する
証明書ピン留めを行う通信は、プロキシが証明書を差し替えた時点で失敗します。特定のMicrosoft証明書を検証するWindowsコンポーネントなどでは、この回避策はなく、除外設定が必要です。3
flowchart TB
accTitle: CAの配布とピン留め通信の除外を分ける
accDescr: TLSインスペクションの証明書エラーではCAの信頼を確認するが、証明書ピン留めを行う通信は差し替え自体が失敗原因となるためインスペクションから除外する
failure["証明書検証エラー"] --> pinned{"証明書をピン留め?"}
pinned -->|"はい"| exclude["インスペクションから除外"]
pinned -->|"いいえ"| store["参照する信頼ストアを確認"]
store --> ca["社内CAの配布を確認"]
図15: 社内CAを配布する対処と、証明書の差し替え自体を避ける対処は別。
Microsoft 365などのSaaS宛トラフィックも、Microsoftはネットワーク層での復号・検査から除外することを推奨しています。8 特定のクラウドサービスだけで証明書エラーが出る場合は、インスペクションの除外リストとピン留めの組み合わせを疑います。
8. 切り分け手順 ── 5ステップで犯人を特定する
ここまでの仕組みを、実際の調査では次の順に確認します。
| 手順 | やること | 分かること |
|---|---|---|
| ① 再現 | 問題のURLへcurl.exe -vやInvoke-WebRequestでアクセス(できれば同じマシン・同じアカウントで) |
アプリ固有の問題か、環境の問題か |
| ② 設定採取 | netsh winhttp show proxy、ユーザー別設定、環境変数の3系統を採取 |
どの系統に何が入っているか |
| ③ アカウント特定 | 対象アプリの実行アカウントを特定(サービスか、タスクスケジューラか、別ユーザーか) | どの設定・どの資格情報で動いているか |
| ④ エラー分類 | 407 / 403 / 名前解決失敗 / タイムアウト / 証明書エラーを区別 | プロキシ認証・ポリシー拒否・経路・TLSインスペクションの切り分け |
| ⑤ プロキシログ | プロキシサーバーのアクセスログで該当時刻を確認 | そもそもプロキシに到達したか、誰として認証されたか |
① 再現: 同じURLでも、ツールの設定系統は揃える
問題のURLへ、できれば同じマシン・同じアカウントからアクセスします。使うツールの違いにも注意します。
| ツール | 調査で意識すること |
|---|---|
Windows同梱のcurl.exe |
-x http://proxy:8080でプロキシを明示できる。TLS検証には通常OSの証明書ストア(Schannel)を使う |
Windows PowerShell 5.1のInvoke-WebRequest |
.NET Framework側の解決。既定はインターネットオプション |
PowerShell 7のInvoke-WebRequest |
.NET側の解決。環境変数を優先 |
「curlは通るのにアプリは通らない」は、設定系統が食い違うヒントです。別のツールで成功したことだけで、アプリも同じ経路を通ったとは判断しません。
② 設定採取: 3系統をまとめて記録する
PowerShellでは、次のように採取できます。ユーザー別設定のHKCUは、このコマンドを実行したアカウントのものです。
# ① ユーザー別(WinINET)設定 ── 実行アカウントのHKCUを読む点に注意
Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable, ProxyServer, ProxyOverride, AutoConfigURL
# ② マシン(WinHTTP)設定
netsh winhttp show proxy
# ③ 環境変数
Get-ChildItem env: | Where-Object Name -match 'proxy'
③ アカウント特定: サービスなら同じアカウントで再確認する
対象がサービス、タスクスケジューラ、別ユーザーによる実行のどれかを特定します。サービスなら、同じアカウントで①の再現と②の採取をやり直します。管理者の自分のセッションでの成功は、LocalSystemの見え方の証明にはなりません。
flowchart TB
accTitle: 実行アカウントを揃えて再現する
accDescr: 管理者のセッションでの採取はサービスから見える設定の証明にならないため、対象の実行アカウントを特定した後、そのアカウントで再現と設定採取を確認し直す
admin["管理者のセッションで確認"] --> identify["対象の実行アカウントを特定"]
identify --> same["同じアカウントで再現・採取"]
same --> compare["設定と資格情報を照合"]
図16: ①②で採った情報は、③で特定した対象アカウントから見た情報かを確かめる。
④ エラー分類: 「つながらない」を分解する
407なら6章のプロキシ認証、証明書エラーなら7章のTLSインスペクションを確認します。タイムアウトなら、プロキシへ到達できていない可能性を第一候補とし、経路・名前解決・ファイアウォールを調べます。403のポリシー拒否も、認証やタイムアウトとは分けます。
flowchart TB
accTitle: エラーから調査先を分ける
accDescr: 通信失敗を407、403、タイムアウトや名前解決失敗、証明書エラーに分け、それぞれ認証、ポリシー拒否、経路、TLSインスペクションを調べる
error["通信の失敗"] --> auth["407ならプロキシ認証"]
error --> deny["403ならポリシー拒否"]
error --> route["時間切れ・名前解決なら経路"]
error --> tls["証明書エラーならTLS"]
図17: ステータスコードや例外を分けると、確認する設定とログを絞れる。
プロキシではなくWindowsファイアウォールの受信規則が原因となるパターンは「Windowsファイアウォールと業務アプリ」で扱います。
⑤ プロキシログ: 到達と認証されたアカウントを確かめる
該当時刻のアクセスログで、プロキシに到達したか、誰として認証されたかを確認します。痕跡がなければ、通信がプロキシへ届いていないものとして、PACのDIRECT、バイパスリスト、環境変数の消し忘れを調べます。
必要ならパケットキャプチャで実際の宛先を確認します。採取方法は「Windowsのパケットキャプチャ実務 ── pktmon・netsh trace・Wiresharkの使い分け」を参照してください。
9. 設計の推奨 ── プロキシを「設定できるアプリ」にする
調査のしやすさは、アプリの設定項目とログで変わります。社内プロキシのある環境へ納めるアプリでは、次の4点を用意します。
既定に従うだけでなく、明示指定と直結も選べるようにする
既定は「OS設定に従う」とし、PACを読めない、サービスで動く、特殊な構成である場合には、設定ファイルからプロキシURL・バイパスリスト・「プロキシを使わない」を指定できるようにします。実装点は5.3節のHttpClientHandler.ProxyとUseProxyです。11
.NET(Core以降)の既定には、5.2節で説明した環境変数の優先もあります。既定に任せる場合も、どの設定が使われるかはその規則に沿って読みます。
社内宛の例外を、導入手順書に書ける形にする
API・DB・ライセンスサーバー等の社内宛通信を、PACのDIRECT、バイパスリスト、NO_PROXYのどれで除外するかを明文化します。NO_PROXYのワイルドカード不可や先頭ドットの意味は、例を添えて示します。5
タイムアウトとリトライも、プロキシ経由を前提にする
プロキシの停止や認証待ちに対して、長い既定タイムアウトを待ち続けるとUIも運用も固まります。接続タイムアウトを短めに分離し、リトライは冪等な要求に限定します。詳細は「HttpClientをusingで囲んではいけない」で扱います。
実際に構成したハンドラーから、経路をログに残す
HttpClient.DefaultProxyだけをログへ出すと、ハンドラーの明示指定やUseProxy = falseを見落とし、食い違う経路を記録します。HttpClientの生成に使ったハンドラーから有効な設定を選び、宛先のバイパス判定も反映することが重要です。
using System.Net.Http;
// handler は HttpClient の生成に使ったものと同じインスタンス
// UseProxy=false なら常に直結。明示指定があればそれが、無ければ DefaultProxy が使われる
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送信 {Target} 経路 {Route} 実行アカウント {User}",
target, route, Environment.UserName);
flowchart TB
accTitle: 通信クライアントの構成から経路を記録する
accDescr: HttpClientの生成に使ったハンドラーから有効なプロキシを選び、宛先のバイパス判定とプロキシ解決を行って、経路と実行アカウントをログへ記録する
handler["生成時と同じハンドラー"] --> effective["UseProxyと明示指定を反映"]
effective --> target["宛先のバイパス判定・解決"]
target --> log["経路とアカウントを記録"]
図18: 既定プロキシだけでなく、クライアント自身の構成を基に経路を記録する。
起動時に主要な宛先の経路と実行アカウントを記録しておくと、8章の①〜③を追いやすくなります。「ブラウザーではつながるのに」と言われたときに、アプリが自分の設定と経路を説明できることが、調査に強い設計です。
10. まとめ
Windowsのプロキシ調査では、まず設定系統・実行アカウント・対象URLを揃えます。
WinINETのユーザー別設定、WinHTTPのマシン設定、環境変数は別の系統です。サービス化では見える設定と資格情報が変わり、.NET Frameworkと.NET(Core以降)でも既定の順序が違います。netsh winhttp set proxyだけではPAC・自動検出・認証を扱えません。
PACはURLごとにプロキシまたはDIRECTを返し、WPADにはネットワーク側の仕掛けが必要です。経路が決まった後も、407のプロキシ認証とTLSインスペクションによる証明書検証は別に確認します。証明書検証は無効化せず、CAを配布し、ピン留めされた通信は除外します。
切り分けは、再現→3系統の設定採取→実行アカウント特定→エラー分類→プロキシログの順です。アプリ側にはプロキシの明示指定と直結、例外設定、タイムアウト、経路ログを用意します。
次に「業務アプリだけつながらない」と相談されたら、最初にこう確認してください。
そのアプリは、誰のアカウントで動いていて、3系統のどのプロキシ設定を読むものですか。
この一問が、調査の入口になります。
関連記事
- HttpClientをusingで囲んではいけない ── C#業務アプリのHTTP通信実務(生成パターン・タイムアウト・リトライ)
- Windowsのパケットキャプチャ実務 ── pktmon・netsh trace・Wiresharkの使い分け
- Windowsファイアウォールと業務アプリ ── 受信規則はインストーラーで登録する
- Windowsサービスの作り方と運用 ── タスクスケジューラとの使い分けからBackgroundServiceのサービス化まで
- 図解でわかるNTLMとKerberos ── なぜ認証はNTLMに「落ちる」のか
- Windows証明書ストア実務ガイド ── ユーザーとコンピューター、どちらに入れるか
関連する相談領域
合同会社小村ソフトでは、「開発機では動くのに客先ネットワークでは通信できない」「サービス化したら外部APIにつながらなくなった」といった、社内プロキシ・認証プロキシ・TLSインスペクション環境でのWindowsアプリの通信トラブル調査と、プロキシ環境を前提にした業務アプリの通信設計(設定項目・タイムアウト・ログ設計)の相談を扱っています。現象の再現手順とログの採取方法を整理するところからで構いません。
参考リンク
-
Microsoft Learn, WinINet vs. WinHTTP. サービスや偽装・セッション分離を必要とするプロセスでなければWinINETを使うという使い分けの指針、資格情報キャッシュ・資格情報プロンプト・サービスサポート・偽装・セッション分離などの機能比較表について。 ↩ ↩2 ↩3
-
Microsoft Learn, About WinHTTP. WinHTTPがサービス・サーバーサイド用途向けに設計されたHTTPスタックであり、サービスアカウントでの実行と偽装をサポートする一方、ブラウザーのCookie・キャッシュ・資格情報・ユーザーのインターネットオプションを共有しないことについて。 ↩ ↩2
-
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
-
Microsoft Learn, WinHttpGetProxyForUrl function. WPADプロトコルの実装として、PACファイルがURLごとに異なるプロキシを返し得るためURL単位で呼び出す必要があること、PAC URLの明示指定とネットワークからの自動検出の両方をサポートすることについて。 ↩ ↩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
-
Microsoft Learn, Configuring Internet Applications. .NET FrameworkでdefaultProxy要素が既定プロキシを定義し、Proxyプロパティを持たないHttpWebRequestが既定プロキシを使うこと、システムのインターネット設定と構成ファイルの設定が組み合わされ構成ファイル側が優先されることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Authentication in WinHTTP. プロキシ認証が必要な場合にステータスコード407とProxy-Authenticateヘッダーが返ること(サーバー認証は401とWWW-Authenticate)、Basic認証とKerberosなどのチャレンジ/レスポンス方式の違い、チャレンジ/レスポンス方式ではユーザー名とパスワードがネットワークを流れないことについて。 ↩ ↩2 ↩3
-
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, 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
-
Microsoft Learn, WinHTTP AutoProxy Support. PACスクリプトがFindProxyForURL(url, host)関数を含み、リクエストごとにプロキシのリストを計算すること、直接接続でよい場合は特別な返り値で示すこと、従来のAutoProxy APIでは自動プロキシがHTTPスタックへ自動統合されておらずアプリ側でWinHttpGetProxyForUrlを呼ぶ必要があることについて。 ↩ ↩2
-
Microsoft Learn, Make HTTP requests with the HttpClient class. HttpClient.DefaultProxyとHttpClientHandler.Proxyの2つの構成方法、Proxy指定が構成ファイルやローカルコンピューターの設定より優先されること、WPADがDNSのwpad名やDHCPを通じてPACファイル(wpad.datなど)を取得する一般的な構成、フラット名・ループバック・ドメインサフィックス一致によるローカル宛バイパス判定について。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, WinHttpOpen function. dwAccessTypeの各値の意味。WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY(Windows 8.1以降)がシステム/ユーザーのプロキシ設定を使ってプロキシを自動決定し、フェールオーバーや認証も自動処理すること、WINHTTP_ACCESS_TYPE_DEFAULT_PROXYが8.1以降では非推奨であることについて。 ↩ ↩2
-
Microsoft Learn, defaultProxy element (network settings). system.net/defaultProxy要素のenabled・useDefaultCredentials属性、proxy・bypasslist・module子要素、要素が空の場合はシステムのプロキシ設定が使われること、.NET 6以降への移行時はHttpClient.DefaultProxyで構成することについて。 ↩ ↩2
-
Microsoft Learn, HttpClientHandler.DefaultProxyCredentials Property. UseProxyがtrueかつProxyがnullでシステム既定のプロキシを使う場合に、その既定プロキシへの認証に使う資格情報を設定するプロパティであることについて。 ↩
-
Microsoft Learn, WebProxy.Credentials Property. CredentialsプロパティがHTTP 407への応答としてプロキシへ送る資格情報であること、多くのクライアントシナリオではサインイン中ユーザーの既定資格情報を使うためUseDefaultCredentialsをtrueに設定するのが推奨であることについて。 ↩
-
Microsoft Learn, Work with existing on-premises proxy servers. アウトバウンドHTTPS通信がプロキシへのCONNECTリクエストで確立されること、成功時はHTTP 200が返り、407(認証要求)や502などの応答はプロキシが通信を許可していないことを示すため、プロキシ側チームとの切り分けに進むべきことについて。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
ネットは使えるのに「インターネットなし」?── WindowsのNCSI・DNS・プロキシ・VPNを切り分ける
ネットは使えるのにWindowsが「インターネットなし」と表示する理由を、NCSIの接続判定から解説します。DNS・プロキシ・VPN・認証Wi-Fiを、設定変更前の確認コマンドとイベントログで切り分けます。
HttpClientをusingで囲んではいけない ── C#業務アプリのHTTP通信実務(生成パターン・タイムアウト・リトライ)
C#のHttpClientは毎回usingで生成するとソケット枯渇、staticにするとDNS変更に追従しません。PooledConnectionLifetimeとIHttpClientFactoryによる正しい生成パターン、タイムアウト設計、リトライまで整理します。
Windowsの名前解決の順序 ── hosts・DNSキャッシュ・LLMNR/mDNS・DoH
「名前解決できない」「一部のPCだけ繋がらない」は、hosts・DNSキャッシュ・DNSサーバー・LLMNR/mDNSのどの層が答えたかで結果が変わります。Windowsの名前解決の順序とDoHが変えるものを仕組みから整理し、層ごとに切り分ける手順を解説します。
Time Travel Debugging ── 長期稼働で再現しない不具合を「録画」して巻き戻す
月に一度しか出ない不具合は、クラッシュダンプでは結果しか写りません。WinDbgのTime Travel Debugging(TTD)で実行を録画して巻き戻す方法を、TTD.exeの録画設計、リングバッファ、TTD.Callsクエリ、ダンプとの使い分けまで解説します。
引数はなぜ壊れるか ── Windowsのコマンドライン引数の規則
Windowsでは引数の配列は存在せず、CreateProcessに渡るのは1本の文字列で、分割は受け取り側が行います。CommandLineToArgvW・CRT・.NETの分割規則と、.NETのArgumentList・C++での正しい組み立て方を解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
不具合調査 / 長期稼働テーマ
再現しにくい不具合、通信停止、長期稼働障害、失敗パス検証を整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- ブラウザーではつながるのに、業務アプリだけ社内プロキシを通れないのはなぜですか?
- ブラウザーは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)とは別物です。まずプロキシが要求する認証方式(Negotiate・NTLM・Basic)をProxy-Authenticateヘッダーで確認し、.NETならHttpClientHandler.DefaultProxyCredentialsやWebProxy.UseDefaultCredentialsで資格情報を渡します。サービスアカウントで動くアプリでは「既定の資格情報」がそのサービスアカウントのものになるため、対話ユーザーでは通るのにサービス化すると407になる、という事象が典型的に起こります。プロキシ側のログで、誰として認証されたかも合わせて確認してください。
- TLSインスペクション型プロキシで証明書エラーになります。証明書検証を無効化してよいですか?
- 無効化は推奨しません。TLSインスペクション型プロキシは通信をいったん復号し、自前のCAで再署名した証明書をクライアントへ提示するため、そのCA証明書が信頼されたルートに入っていないと検証エラーになります。正しい対処は、社内CA証明書をWindowsの証明書ストア(通常はローカルコンピューターの信頼されたルート証明機関)へ配布することです。コードで検証を無効化すると、社外ネットワークで使われたときに中間者攻撃を検出できなくなり、脆弱性として残り続けます。