Proxy ארגוני ו-Windows apps —‏ WinINET, WinHTTP ו-.NET

· עודכן בתאריך: · · Windows, Proxy, WinHTTP, WinINET, .NET, HttpClient, PAC, WPAD, רשת

היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 20 Aug 2026)
פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22176220)

מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.

Go Komura (2026). Proxy ארגוני ו-Windows apps —‏ WinINET, WinHTTP ו-.NET. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22176220 https://comcomponent.com/he/blog/windows-proxy-wininet-winhttp-dotnet/

DOI (הגרסה האחרונה)
10.5281/zenodo.22176220
DOI (הגרסה הזו)
10.5281/zenodo.22176221

“בדפדפן אתרים חיצוניים נפתחים, ורק האפליקציה העסקית לא מגיעה ל-API החיצוני.” “על מחשב הפיתוח זה עובד, וברשת של הלקוח זה נופל ב-timeout.” “כשמריצים ידנית התקשורת עוברת, וברגע שהופכים את זה ל-Windows service זה נכשל.” — כשמריצים אפליקציה עסקית מאחורי proxy ארגוני, אלו כמעט תלונות ברירת המחדל.

ברוב המקרים זו לא תקלה בשרת ה-proxy וגם לא באג באפליקציה. ב-Windows יש כמה מקורות נפרדים שכולם נקראים “הגדרות proxy”, ומי קורא איזו הגדרה תלוי באפליקציה (ב-HTTP stack שלה) וב-account שבו היא רצה — זה ה-mismatch. ההגדרות שהדפדפן קורא, שאלה ש-service קורא, ואלה ש-HttpClient של .NET קורא, יכולות להיות שלושה דברים שונים. ברגע שהמבנה הזה בראש, הבידוד של “בדפדפן זה עובד, אבל…” נהיה מהיר בהרבה.

המאמר מיועד לאנשי IT בארגונים קטנים ובינוניים ולמפתחי Windows apps. הוא מחבר לתמונה אחת את שלושת מקורות הגדרות ה-proxy —‏ WinINET, WinHTTP ו-environment variables —‏ autoconfig דרך PAC ו-WPAD, את ההבדל ב-proxy resolution בין .NET Framework ל-.NET (Core ואילך), authenticating proxy (407), TLS inspection, ואת סדר ה-isolation בשטח. דפוסי יצירת HttpClient ותכנון timeout עצמם מכוסים ב-אל תעטפו HttpClient ב-using, ולכן כאן מתמקדים ב-proxy resolution.

1. בשורה התחתונה

  • הגדרות proxy ב-Windows הן לא דבר אחד; יש לפחות שלושה מקורות. (1) הגדרות WinINET לפי user (מסך Proxy באפליקציית Settings = Internet Options הישן), (2) הגדרות machine של WinHTTP (netsh winhttp), ו-(3) ה-environment variables HTTP_PROXY / HTTPS_PROXY. מי קורא מה, מחליטה האפליקציה.12
  • ה-“Proxy” שרואים ב-Settings הוא הגדרות per-user של WinINET. דפדפנים ואפליקציות אינטראקטיביות קוראים אותן; Windows services לא. WinINET לא נתמך לשימוש ב-service; ל-service זה תפקיד של WinHTTP.13
  • הסיבה הנפוצה ביותר ל-“עובד ידנית ולא כ-service” היא account אחר. LocalSystem ו-service account לא רואים את ה-proxy ה-per-user שמנהל הגדיר על המסך שלו.34
  • netsh winhttp set proxy הוא static; אין שם PAC, auto-detect או proxy authentication. אם רוצים להגדיר PAC או WPAD לכל מכונה, זה צד netsh winhttp set advproxy.42
  • תוצאת PAC משתנה לפי URL. הפונקציה FindProxyForURL בקובץ ה-PAC מקבלת URL ו-host ומחזירה רשימת proxy או חיבור ישיר (DIRECT). “האתר ההוא עובר, ורק ה-API הזה לא” יכול להיות ענף ב-PAC.56
  • HttpClient ב-.NET (Core ואילך) מאתחל את ה-proxy ברירת המחדל בסדר environment variables → הגדרות proxy של ה-user ב-Windows. אם אחד מ-HTTP_PROXY, HTTPS_PROXY או ALL_PROXY מוגדר, הוא מנצח את הגדרות ה-OS, ולכן יכול לקרות “מישהו השאיר environment variable”.7
  • ברירת המחדל של .NET Framework היא Internet Options של ה-account שרץ, ואפשר לדרוס אותה ב-defaultProxy ב-app.config. הגדרות קובץ ה-config מנצחות את הגדרות המערכת.89
  • 407 הוא שגיאת authentication של ה-proxy; זה לא 401 (authentication של השרת). ה-schemes כוללות Negotiate, NTLM ו-Basic, וב-.NET מעבירים credentials עם DefaultProxyCredentials או WebProxy.UseDefaultCredentials. שימו לב שתחת service account תוכן “default credentials” משתנה.101112
  • Proxy של TLS inspection מחזיק רק כסט עם הפצת ה-CA הפנימי. מכונות ו-runtimes שלא קיבלו אותו מקבלים certificate validation error. פותרים בהפצה ל-certificate store, לא בכיבוי validation באפליקציה.134

במשפט אחד: בכל פעם שאומרים “בדקתי את הגדרות ה-proxy”, תמיד להיות מסוגלים לומר איזה משלושת המקורות בדקתם, ומאיזה account — זה נושא המאמר.

2. ב-Windows יש שלושה מקורות של “הגדרות proxy”

קודם המפה הכוללת. הנתיבים ש-Windows app משתמש בהם כדי למצוא proxy ארגוני נופלים לשלושת המקורות האלה.

מקור הגדרות איפה מגדירים / הפקודה Scope מי קורא בעיקר
(1) WinINET (Internet Options) Settings → Network & internet → Proxy, inetcpl.cpl per-user (ברירת מחדל) דפדפנים, desktop apps אינטראקטיביות, ברירת המחדל של .NET Framework
(2) WinHTTP (הגדרות machine) netsh winhttp set proxy / set advproxy machine Windows services, חלק מרכיבי ה-OS
(3) Environment variables HTTP_PROXY / HTTPS_PROXY / ALL_PROXY / NO_PROXY process (עוברים בירושה לפי איפה הוגדרו) HttpClient ב-.NET (Core ואילך), curl, כלים חוצי-פלטפורמה כמו Node.js ו-Python

(1) הוא מה שאנשים מזהים בדרך כלל כ-“הגדרות ה-proxy של Windows”; בפועל זו תצורת WinINET. היסטורית אלו Internet Options של Internet Explorer, וכברירת מחדל הן נשמרות לפי user.4

(2) הוא ברירת המחדל לכל מכונה להקשרים כמו service שבהם “אין user מחובר”. (3) הוא בעיקר מוסכמה של כלים שמגיעים מעולם חוצה-הפלטפורמות; ב-Windows גם .NET (Core ואילך) ו-curl וכדומה קוראים אותם.7

הנקודה החשובה: מי קורא איזה מקור, מחליטה האפליקציה, לא צד ההגדרות. אם האפליקציה משתמשת ב-WinINET בפנים היא קוראת (1); אם WinHTTP, (2) (או override ספציפי לאפליקציה); אם .NET (Core ואילך), (3) ואז (1). לכן בדרך כלל זה לא “הגדרות ה-proxy נכונות ועדיין לא מתחבר”; המציאות היא “המקור שהאפליקציה קראה היה מקור אחר מזה שבדקתם”.

שלושה מקורות של הגדרות proxy ב-WindowsWinINET הוא הגדרות per-user ו-Internet Options, WinHTTP הוא ברירת מחדל ברמת המכונה דרך netsh, ו-environment variables הם ב-scope של process. איזה מקור נקרא מחליטה האפליקציה, לא צד ההגדרותאיזה מקור?הגדרות WinINET לפי userהגדרות machine של WinHTTPHTTP_PROXY ודומיודפדפנים ו-desktop appsservices וחלק מרכיבי ה-OS.NET Core+ ו-curl

איור 1: שלושה מקורות זה לצד זה. האפליקציה בוחרת איזה מהם היא קוראת.

אם מפעילים את ה-Group Policy “Make proxy settings per-machine (rather than per-user)”, אפשר להעביר את (1) לרמת מכונה ולהחיל אותן הגדרות על כל user. עם MDM (Intune וכדומה) אפשר להגדיר לכל מכשיר עם NetworkProxy CSP.4

3. WinINET ו-WinHTTP —‏ desktop אינטראקטיבי מול service

3.1. למה כל אחד מיועד

WinINET ו-WinHTTP שניהם HTTP client stacks מובנים ב-Windows, אבל הם מניחים שימושים שונים.

  • WinINET: מכוון ל-desktop apps אינטראקטיביות. הוא יורש אוטומטית את Internet Options של ה-user (proxy, cookies, credential cache) ואף יכול להציג UI להזנת credentials אם צריך. שימוש ב-service או ב-process דמוי-service לא נתמך.1
  • WinHTTP: מכוון ל-services ולצד השרת. הוא תומך בהרצה תחת service account, ב-impersonation של thread וב-session isolation; בתמורה הוא לא משתף את הגדרות הדפדפן של ה-user, cookies או credentials. גם לא מציג UI.3

ההנחיה של Microsoft עצמה ברורה באותה מידה: “השתמשו ב-WinINET אלא אם אתם רצים בתוך service, או ב-process דמוי-service שצריך session isolation ו-impersonation” — כלומר, אם זה service, משתמשים ב-WinHTTP.1

WinINET לאפליקציות אינטראקטיביות, WinHTTP ל-servicesWinINET יורש את Internet Options של ה-user המחובר ואינו נתמך ב-service. WinHTTP רץ תחת service account בלי UI ואינו משתף את הגדרות הדפדפן של ה-userכןservice או דמוי-servicedesktop app אינטראקטיבית?WinINETWinHTTPקורא Internet Options של ה-userהגדרות machine, בלי UI

איור 2: אפליקציות אינטראקטיביות משתמשות ב-WinINET. service משתמש ב-WinHTTP.

3.2. netsh winhttp: הפעולות הבסיסיות

את ה-proxy ברירת המחדל ברמת המכונה של 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 הוא static. הוא לא מטפל ב-auto-detect של proxy, לא בציון URL של PAC, ולא ב-proxy authentication.4
  2. import proxy source=ie מעתיק רק את ההגדרות הסטטיות באותו רגע; הוא לא עוקב אחרי שינויים מאוחרים בצד Internet Options. כשצריך תצורה לכל מכונה שכוללת PAC או auto-detect, מגדירים את ההגדרות המפורטות בצורת JSON (Proxy, ProxyBypass, AutoconfigUrl, AutoDetect) עם netsh winhttp set advproxy.2

3.3. ה-pitfall הנפוץ: service לא קורא את הגדרות ה-IE של ה-user

הדפוס שרואים הכי הרבה בשטח, לפי סדר הזמן, נראה כך.

  1. מפתח מריץ את הכלי על המחשב שלו → הגדרות ה-proxy ה-per-user (1) נכנסות לתוקף וזה עובד
  2. בייצור משאירים אותו resident כ-Windows service (איך בונים ומפעילים Windows services) תחת LocalSystem
  3. ההגדרות שנראות מ-LocalSystem הן דבר אחר (הגדרות per-user לא נראות, והגדרות machine של WinHTTP לא מוגדרות = DIRECT) → מנסה חיבור ישיר ל-API החיצוני ונופל ב-timeout

זה לא “לא עובד אף שזו אותה מכונה”; גם באותה מכונה, account אחר אומר שסט אחר של הגדרות proxy נראה. ל-process שמתקשר גם כשאף user לא מחובר, הגישה הנכונה היא להכין הגדרות לכל מכונה בצורה שה-HTTP stack של אותו process באמת קורא. לאפליקציה native או לרכיב Windows שמשתמש ב-WinHTTP, הגדרות WinHTTP של netsh נכנסות לתוקף.4 HttpClient ב-.NET (Core ואילך), לעומת זאת, לא קורא את הגדרות ה-machine של WinHTTP (ראו פרק 5), ולכן ל-service ב-.NET מגדירים system environment variable (HTTPS_PROXY וכדומה) או מציינים HttpClientHandler.Proxy במפורש מהגדרות האפליקציה.

התקלה קורה גם בכיוון ההפוך. אם אופים proxy סטטי למחשב נייד שנע בין הרשת הארגונית לחוץ עם netsh winhttp set proxy, אותו proxy לא נגיש מחוץ לחברה והתקשורת מתה לגמרי. מתייחסים להגדרה סטטית ברמת מכונה כאמצעי שמכוון לשרתים שתצורת הרשת שלהם לא משתנה.4

למה service לא רואה את הגדרות ה-IE של ה-userהרצה ידנית כ-user קוראת הגדרות WinINET per-user ועובדת. כ-LocalSystem ההגדרות האלה לא נראות. אפליקציית WinHTTP native אז הולכת אחרי הגדרות machine לא מוגדרות (DIRECT). service של .NET Core+ עדיין משתמש ב-environment variables או ב-handler.Proxy מפורש ואינו עובר ל-netsh winhttpWinHTTP.NET Core+הרצה ידנית כ-userהגדרות WinINET per-user חלותWindows service כ-LocalSystemהגדרות per-user לא נראותאיזה HTTP stack?WinHTTP לא מוגדר = DIRECTenvironment variables או handler.Proxyה-API החיצוני נופל ב-timeout

איור 3: אותה מכונה, account אחר — נראות הגדרות proxy אחרות.

4. PAC ו-WPAD — מה באמת קורה ב-automatic configuration

4.1. קובצי PAC ו-FindProxyForURL

קובץ PAC (Proxy Auto-Configuration) הוא JavaScript (ECMAScript) שמחשב “איזה proxy להשתמש ל-URL הזה”, והוא תמיד מכיל פונקציה בשם FindProxyForURL(url, host). הפונקציה מחזירה רשימת proxy שיש להשתמש בהם, או ערך החזרה מיוחד (DIRECT) שאומר שמותר להתחבר ישירות בלי proxy.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";
}

שתי תוצאות מעשיות יוצאות מזה.

  • Proxy resolution חייב לקרות לכל URL. כי PAC יכול להחזיר proxy אחר או חיבור ישיר לפי ה-URL (ה-host), גם תכונת ה-auto proxy של WinHTTP מתוכננת להעביר את ה-URL של הבקשה ולשאול בכל פעם.6 “הדפדפן רואה אתר אחר” אינו הוכחה שה-API הבעייתי לוקח את אותו נתיב.
  • DIRECT הוא הוראה “ללכת בלי proxy”. אם traffic שאמור להיות פנימי לא מופיע בלוג של ה-proxy בכלל, חושדים קודם ש-PAC החזיר DIRECT (או שפגע ב-bypass list).

4.2. Auto-detect דרך WPAD

מפעילים “Detect settings automatically” והמכונה מחפשת את מיקום קובץ ה-PAC בפרוטוקול WPAD (Web Proxy Auto-Discovery). בתצורה טיפוסית DHCP מוסר URL של PAC, או משתמשים ב-DNS כדי לחפש host בשם wpad וה-PAC מורד מ-URL כמו http://wpad/wpad.dat.14

כלומר, “auto-detect” הוא לא קסם; זה מנגנון שעובד רק ברשת שכבר הקימה סידור WPAD ב-DHCP/DNS. הפעלת auto-detect לבדו ברשת בלי סידור כזה רק מוסיפה זמן המתנה לכישלון הגילוי.

PAC פותר proxy לכל URL, WPAD רק מוצא את ה-PACFindProxyForURL מקבל URL ו-host ומחזיר רשימת proxy או DIRECT. WPAD מאתר את ה-PAC רק דרך DHCP או DNS. client שאינו יכול להעריך PAC נופל ל-proxy סטטי או ל-environment variablesרשימת proxyDIRECTURL הבקשהFindProxyForURLלעבור דרך proxyלהתחבר בלי proxyWPAD דרך DHCP או DNSclient שאינו מעריך PACהגדרות סטטיות או environment variables

איור 4: PAC מחליט לכל URL. WPAD רק מוצא את קובץ ה-PAC.

4.3. מה קורה אצל client שלא יודע להריץ PAC

לא כל client יכול להעריך PAC.

  • ההגדרות הסטטיות של netsh winhttp set proxy לא מעריכות PAC.4
  • כלים בסגנון ה-environment variable HTTP_PROXY יכולים, ככלל, לכתוב רק URL קבוע של proxy (אין מקום לכתוב URL של PAC).7
  • לאפליקציה native שמשתמשת ב-WinHTTP ישירות, זה תלוי איך נפתחה ה-session. אפליקציה שנפתחה עם WinHttpOpen ב-Windows 8.1 ואילך עם ציון WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY גורמת ל-WinHTTP לפתור אוטומטית את הגדרות ה-proxy של המערכת/ה-user (כולל WPAD/PAC) לכל בקשה.15 אם נפתחה עם WINHTTP_ACCESS_TYPE_DEFAULT_PROXY הישן יותר (deprecated מ-8.1 ואילך) או דומה, auto proxy לא משולב ב-HTTP stack, והאפליקציה צריכה לקרוא בעצמה ל-WinHttpGetProxyForUrl ולהחיל את התוצאה על הבקשה. כלומר, ביישום ישן יותר, PAC יכול להיות נוכח ועדיין לא בשימוש.5

“הדפדפן הולך ל-proxy הנכון דרך PAC, אבל האפליקציה העסקית לא קוראת PAC ומנסה חיבור ישיר ונכשלת” — זו עוד אי-התאמה קלאסית. ברשת שמופעלת ב-PAC צריך להחליט על fallback — הגדרות סטטיות או environment variables — ל-clients שלא יכולים לקרוא PAC.

5. Proxy resolution ב-.NET —‏ Framework ו-Core+ הם לא אותו דבר

אילו הגדרות proxy אפליקציית .NET קוראת נבדל כברירת מחדל בין .NET Framework ל-.NET (Core ואילך). מערבבים את השניים ובודקים אפליקציית .NET 8 בידע של עידן Framework ומפספסים.

5.1. .NET Framework — ברירת המחדל היא Internet Options, ו-defaultProxy דורס

ב-.NET Framework, HttpWebRequest ו-HttpClient שיושב עליו משתמשים ב-proxy ברירת המחדל אלא אם מציינים Proxy במפורש. ה-proxy ברירת המחדל מוכרע בשילוב של הגדרות האינטרנט של המערכת (הגדרות WinINET של ה-account שרץ) וקובץ ה-config, והגדרות קובץ ה-config מנצחות.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 ריק והגדרות המערכת (Internet Options) בשימוש; כותבים proxyaddress וכדומה ואלו מנצחות. מהתוכנית אפשר להחליף את אותה ברירת מחדל ב-WebRequest.DefaultWebProxy.98

ה-pitfall מפרק 3.3 חל גם כאן. כי ברירת המחדל היא “Internet Options של ה-account שרץ”, אפליקציית .NET Framework שרצה תחת service account קוראת סט הגדרות אחר (בדרך כלל ריק) מאלו שנראות בשולחן של המנהל.

5.2. .NET (Core ואילך) — קודם environment variables, אחר כך הגדרות ה-user ב-OS

ל-HttpClient ב-.NET (Core ואילך) יש property סטטי HttpClient.DefaultProxy. אלא אם ה-handler מציין proxy במפורש, כל מופע HttpClient משתמש בו. כלל האתחול ב-Windows הוא קרא environment variables, ואם הם לא מוגדרים קרא את הגדרות ה-proxy של ה-user.7

ה-environment variables שבשימוש הם כדלקמן.7

Environment variable משמעות
HTTP_PROXY Proxy לבקשות HTTP
HTTPS_PROXY Proxy לבקשות HTTPS
ALL_PROXY Fallback כאשר האמור לעיל לא מוגדר
NO_PROXY רשימה מופרדת בפסיקים של hosts שלא צריכים להשתמש ב-proxy

שלושה דברים לשים לב.

  • אם אחד מ-HTTP_PROXY, HTTPS_PROXY או ALL_PROXY מוגדר, הוא מנצח את הגדרות ה-proxy בצד ה-OS. הגדרת NO_PROXY בלבד לא מגדירה proxy מ-environment variables, וב-Windows ממשיכים להשתמש בהגדרות ה-proxy של ה-user ב-OS. “הגדרות שלא רואים” כמו השארת HTTPS_PROXY כ-system environment variable אחרי ניסוי ישן, או תבנית CI/CD שמזריקה אותו, הן מקור קלאסי לתקלות.
  • NO_PROXY לא תומך ב-wildcards (*). כדי להתאים subdomain, שמים נקודה מובילה (.example.com מתאים ל-www.example.com אבל לא ל-example.com עצמו).7
  • מחוץ ל-Windows (Linux containers וכדומה), אם ה-environment variables לא מוגדרים זה מאותחל בלי proxy. שינוי התנהגות ברירת המחדל של אותה אפליקציה בין Windows ל-Linux הוא דבר לאשר בזמן מעבר ל-container.7

5.3. ציון מפורש — HttpClientHandler.Proxy ו-UseProxy

בכל runtime, העדיפות הגבוהה ביותר היא ציון מפורש על ה-handler. ציון HttpClientHandler.Proxy מנצח הגדרות OS וקובץ config, ו-UseProxy = false לא משתמש ב-proxy בכלל.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, ל-bypass אוטומטי של יעדים מקומיים יש כללים. שם שטוח בלי נקודה, כתובת loopback, יעד שמתאים ל-domain suffix של המכונה עצמה וכדומה יכולים להיחשב “local”.14 תופעות כמו “ההתנהגות משתנה אם מציינים כתובת IP” או “פתאום התחיל לעבור ב-proxy כשהשתמשתי ב-FQDN” יכולות להיגרם מהשיפוט הזה.

סדר העדיפות הוא כדלקמן.

עדיפות (גבוהה → נמוכה) .NET Framework .NET (Core ואילך)
1 ציון מפורש כמו HttpClientHandler.Proxy אותו דבר
2 defaultProxy ב-app.config השמה ל-HttpClient.DefaultProxy
3 Internet Options של ה-account שרץ Environment variables (HTTP_PROXY ואחרים)
4 — הגדרות proxy של ה-user ב-Windows
Proxy resolution ברירת מחדל ב-Framework מול Core ואילךHttpClientHandler.Proxy מפורש תמיד מנצח. Framework אז משתמש ב-app.config defaultProxy וב-Internet Options של ה-account שרץ. Core ואילך משתמש בהשמה ל-HttpClient.DefaultProxy, אחר כך environment variables, אחר כך הגדרות proxy של ה-user ב-WindowsFrameworkCore ואילךhandler.Proxy מפורשה-proxy הזה בשימושאין Proxy מפורשאיזה runtime?app.config defaultProxyInternet Options של ה-accountHttpClient.DefaultProxyHTTP_PROXY ודומיוהגדרות proxy של ה-user ב-Windows

איור 5: ציון מפורש תמיד מנצח. נתיב ברירת המחדל נבדל לפי runtime.

6. Authenticating proxy — 407 שייך ל-proxy, לא לשרת

6.1. לא מבלבלים 407 עם 401

כשמנסים לעבור דרך proxy שדורש authentication, ה-proxy מחזיר status code 407 (Proxy Authentication Required) וכותרת Proxy-Authenticate שמונה את ה-schemes הזמינות. זה דבר אחר מדרישת ה-authentication של שרת היעד (401 ו-WWW-Authenticate); הצד שמעבירים אליו credentials והמקום שמגדירים אותם שניהם שונים.10

407 הוא ה-proxy, 401 הוא שרת היעד407 ו-Proxy-Authenticate באים מה-proxy. 401 ו-WWW-Authenticate באים משרת היעד. ה-credentials והמקום שמגדירים אותם נבדליםה-proxyהיעדבקשה יוצאתמי דורש authentication?407 + Proxy-Authenticate401 + WWW-AuthenticateDefaultProxyCredentials

איור 6: 407 הוא authentication של ה-proxy. 401 הוא authentication של השרת.

ה-schemes כוללות Basic, ששולח את שם המשתמש והסיסמה כפי שהם, ו-schemes מסוג challenge/response כמו Negotiate (Kerberos/NTLM). ב-challenge/response הסיסמה עצמה לא נוסעת ברשת, וה-authentication מסתיים בכמה חילופים.10 מנגנון ה-scheme שאליה הוא “נופל” מכוסה בפירוט רב יותר ב-NTLM ו-Kerberos מוסברים בתרשימים.

6.2. איך מעבירים credentials ב-.NET

כשרוצים להשתמש ב-proxy ברירת המחדל שמגיע מהגדרות ה-OS ולהעביר רק את ה-authentication, משתמשים ב-HttpClientHandler.DefaultProxyCredentials. אלו ה-credentials שנשלחים ל-proxy ברירת מחדל זה כאשר UseProxy = true ו-Proxy = null (= ה-proxy ברירת המחדל של המערכת).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);

כשמציינים את ה-proxy במפורש, שמים את ה-credentials בצד WebProxy. בתרחישי client רבים ההמלצה היא להשתמש ב-default credentials של ה-user המחובר ולא בשם משתמש וסיסמה אישיים, ו-WebProxy.UseDefaultCredentials = true הוא זה.12

6.3. בעיית 407 של service account

ה-account שרץ חשוב גם כאן. “Default credentials” פירושו ה-credentials של ה-account שמריץ את ה-process. מריצים כמשתמש אינטראקטיבי וה-authentication ל-proxy הוא כאותו user; מריצים כ-service LocalSystem והוא כ-computer account.

  • אם ה-proxy מאמת users דרך Active Directory, הוא לא יכול לאמת computer account או local account, ו-407 נמשך ברגע שהופכים את האפליקציה ל-service
  • להפך, בחלק מהסביבות יש פטור authentication בצד ה-proxy ל-services (לפי IP מקור או לפי account)

לכן חקירת 407 לא נסגרת על “הגדרות האפליקציה” לבד; זה סט עם בדיקת תכנון בצד התשתית: האם ה-proxy יכול לאמת את ה-account שרץ. לאפליקציה שתהפכו ל-service, צריך להחליט בשלב התכנון אחד מ: להריץ תחת domain service account (gMSA וכדומה), לשים פטור authentication בצד ה-proxy, או להקים proxy ממסר פנימי שלא דורש authentication.

יש גם סגנון שמשבץ credentials ב-environment variable, כמו HTTP_PROXY=http://user:pass@proxy:80807, אבל אז סיסמה בטקסט גלוי חשופה ב-environment variable (= מידע process), ולכן זה לא מומלץ להפעלה שוטפת.

7. HTTPS ו-proxy —‏ CONNECT tunnel ו-TLS inspection

7.1. HTTPS דרך proxy עובר ב-tunnel

כשמשתמשים ב-proxy ל-HTTPS, ה-client שולח תחילה ל-proxy בקשת CONNECT destination-host:443, וה-proxy פותח TCP tunnel. בהצלחה ה-proxy מחזיר 200, ואחרי זה ה-client ושרת היעד מבצעים את ה-TLS handshake בתוך ה-tunnel. אם ה-tunnel לא נפתח, ה-proxy מחזיר 407 (נדרש authentication), 502 או דומה.16

במודל זה ה-proxy לא יכול לקרוא את תוכן ה-tunnel (HTTPS מוצפן). מה שנשאר בלוג של ה-proxy הוא שם ה-host של היעד והאם החיבור הצליח; נתיב ה-URL לא נראה — זו התנהגות proxy מסוג “passthrough”.

HTTPS דרך proxy הוא CONNECT tunnelה-client שולח CONNECT ל-proxy, ה-proxy פותח TCP tunnel ומחזיר 200, ואז ה-client והיעד מבצעים TLS handshake ב-tunnel. לוג ה-proxy רואה את ה-host, לא את נתיב ה-URLCONNECT host:443200 ו-TCP tunnelTLS ב-tunnelclientproxyיעדלוג: host והצלחה בלבד

איור 7: Proxy מסוג passthrough רואה את ה-host, לא את הנתיב המוצפן.

7.2. TLS inspection ו-certificate errors

Proxies של מוצרי אבטחה, לעומת זאת, כוללים סוג TLS inspection (SSL decryption, break and inspect) שמסיים TLS, בודק את התוכן, ומצפין מחדש לפני העברה. בסכמה זו ה-server certificate שמוצג ל-client אינו האמיתי; הוא מוחלף ב-certificate שנחתם מחדש על ידי ה-CA של ה-proxy.13

ההנחה שמחזיקה את התצורה הזו היא אפוא “ה-CA certificate של ה-proxy הופץ ל-trusted roots של כל client”. במכונה שלא קיבלה אותו, או ב-runtime שלא מסתכל על ה-certificate store של Windows (כלים עם trust store משלהם), מקבלים certificate validation error. ב-.NET זה בדרך כלל עולה כ-HttpRequestException שעוטף AuthenticationException (הודעה מסוג “the remote certificate is invalid”).

עקרונות התיקון הם כדלקמן.

  • מפיצים את ה-CA הפנימי ל-store “Trusted Root Certification Authorities” של Local Computer. הפיצול בין user store ל-computer store מכוסה ב-ה-certificate store של Windows בפועל.
  • לא מכבים certificate validation בקוד. פתרון עוקף שמחזיר תמיד true מ-ServerCertificateCustomValidationCallback הופך לאפליקציה פגיעה שאינה יכולה לגלות MITM ברגע שהיא יוצאת לרשת חיצונית.
  • Traffic עם certificate pinning أصلاً לא ניתן ל-inspection. חיבורים שמוודאים certificate ספציפי של Microsoft, כמו שחלק מרכיבי Windows עושים, נכשלים ברגע שה-proxy מחליף את ה-certificate, ואין workaround מלבד exclusion.4 ל-traffic שמיועד ל-SaaS כמו Microsoft 365, Microsoft עצמה ממליצה להחריג אותו מ-decrypt-and-inspect בשכבת הרשת.13

תסמין “כל אתר פנימי נראה, ורק שירות ענן מסוים מייצר certificate error באפליקציה” צריך לגרום לחשוד קודם בשילוב של רשימת ה-exclusion של TLS inspection וה-pinning.

Proxy של TLS inspection חותם מחדש את ה-certificateה-proxy מסיים TLS, בודק את התוכן, ומציג certificate שנחתם מחדש על ידי ה-CA שלו. ה-validation מחזיק רק אם אותו CA ב-trusted roots. לא מכבים validation בקודה-CA ב-trusted rootsה-CA חסרserver certificate אמיתיproxy של TLS inspectionנחתם מחדש על ידי ה-CA של ה-proxyvalidation של ה-clientהצלחהcertificate errorמפיצים את ה-CA ל-store

איור 8: ה-inspection עובד רק כסט עם הפצת ה-CA הפנימי.

8. Isolation — חמישה צעדים עד שמזהים מי אשם

חוקרים “לא יכול להתחבר” באופן מכני בסדר הזה.

צעד מה עושים מה לומדים
(1) שחזור לגשת ל-URL הבעייתי עם curl.exe -v או Invoke-WebRequest (עדיף באותה מכונה, תחת אותו account) אם זו בעיית אפליקציה או בעיית סביבה
(2) איסוף הגדרות לאסוף את שלושת המקורות: netsh winhttp show proxy, ההגדרות per-user, ו-environment variables מה יש באיזה מקור
(3) זיהוי ה-account לזהות את ה-account שבו רצה האפליקציה (service, Task Scheduler, user אחר) תחת אילו הגדרות ואילו credentials היא רצה
(4) סיווג השגיאה להבחין בין 407 / 403 / כשל name resolution / timeout / certificate error לבודד proxy authentication, דחיית policy, נתיב ו-TLS inspection
(5) לוג ה-proxy לבדוק את הזמן המתאים ב-access log של שרת ה-proxy אם הגיע ל-proxy בכלל, וכמי אומת

אפשר לאסוף את (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.exe המובנה ב-Windows יכול לציין proxy במפורש עם -x http://proxy:8080, ול-TLS validation הוא בדרך כלל משתמש ב-certificate store של ה-OS (Schannel). Invoke-WebRequest של Windows PowerShell 5.1 הולך אחרי צד .NET Framework (Internet Options כברירת מחדל); PowerShell 7 הולך אחרי צד .NET (environment variables תחילה). “curl עובד והאפליקציה לא” עצמו הוא רמז לאי-התאמה בין מקורות תצורה.
  • אם היעד ב-(3) הוא service, בודקים מחדש את (1) ו-(2) תחת אותו account כמו ה-service. בדיקה ב-session של המנהל עצמו אינה הוכחה למה ש-LocalSystem רואה.
  • בסיווג השגיאה ב-(4), לוקחים את פרק 6 (authentication) כמועמד ראשון ל-407, פרק 7 (TLS inspection) ל-certificate error, ו-“לא מגיע ל-proxy” (נתיב, name resolution, firewall) ל-timeout. הדפוס שבו הסיבה היא inbound rule של Windows Firewall ולא ה-proxy מכוסה ב-Windows Firewall ואפליקציות עסקיות.
  • אם מגיעים ל-(5) ועדיין אין עקבות בלוג של ה-proxy, ה-traffic מעולם לא הגיע ל-proxy. חושדים בהחלטת DIRECT של PAC, ב-bypass list, או ב-environment variable שנשאר, ואם צריך מאשרים את היעד בפועל ב-packet capture (packet capture ב-Windows בפועל — בחירה בין pktmon, netsh trace ו-Wireshark).
חמישה צעדים לבידוד כשל proxyמשחזרים תחת אותו account, אוספים את שלושת מקורות ההגדרות, מזהים את ה-account שרץ, מסווגים את השגיאה, ואז בודקים את לוג ה-proxyשחזור עם curlאיסוף שלושה מקורותזיהוי ה-accountסיווג השגיאהבדיקת לוג ה-proxy407: authenticationcertificate error: inspectiontimeout: לא הגיע

איור 9: הולכים את חמשת הצעדים לפי הסדר. מחלקת השגיאה בוחרת את הפרק הבא.

9. המלצה לתכנון — אפליקציה שאפשר להגדיר עליה את ה-proxy

הופכים את הליך החקירה והוא הופך להנחיית תכנון בצד האפליקציה. ל-Windows app שתספקו לסביבה עם proxy ארגוני, מומלץ כדלקמן.

  1. הופכים את ה-proxy לניתן להגדרה מהגדרות האפליקציה. ברירת המחדל היא “ללכת אחרי הגדרות ה-OS”. ברוב הסביבות ברירת המחדל מספיקה; רק בסביבות החריגות — אי אפשר לקרוא PAC, רץ כ-service, תצורת proxy מיוחדת — מאפשרים לציין URL של proxy, bypass list, ו-“אל תשתמש ב-proxy” מקובץ הגדרות. HttpClientHandler.Proxy / UseProxy בסעיף 5.3 הוא נקודת המימוש.14
  2. כותבים איך יעדים פנימיים (API, databases, שרתי רישוי וכדומה) מטופלים כ-exceptions של proxy. שמים בצורה שאפשר לכתוב בנוהל הפריסה אם הם מוחרגים על ידי PAC DIRECT, bypass list, או NO_PROXY. כללי ההתאמה של NO_PROXY (בלי wildcards, מה נקודה מובילה אומרת) מובנים לא נכון בהרחבה, ולכן מצרפים דוגמאות.7
  3. מתכננים timeout ו-retry בהנחה שעוברים דרך proxy. אם ה-proxy למטה או תקוע ב-authentication, מימוש שמחכה ל-timeout ברירת מחדל ארוך מקפיא גם את ה-UI וגם את ההפעלה. מפרידים connection timeout קצר יותר, ומגבילים retry לבקשות idempotent (פרטי תכנון ב-אל תעטפו HttpClient ב-using).
  4. רושמים בלוג “איזה proxy היה בשימוש”. הופכים את האפליקציה עצמה ליכולה לענות על השאלה הראשונה של חקירת כשל.

לוג כמו ב-(4) כבר יעיל אם הוא רושם רק את תוצאת ה-resolution. הנקודה היא לגזור את הנתיב מההגדרות (ה-handler) שבאמת השתמשתם בהן כדי להגדיר את ה-client. אם רושמים HttpClient.DefaultProxy ישירות, תרשמו ערך שאינו מסכים עם הנתיב בפועל כאשר ה-handler מציין 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);

אם בהפעלה רושמים פעם אחת “נתיב” ו-“account שרץ” ליעדים העיקריים, הצעדים (1) עד (3) של פרק 8 מסתיימים רק בקריאת הלוג. כשאומרים לכם “עובד בדפדפן, אבל…”, היכולת לומר מצד האפליקציה “השתמשתי בהגדרה הזו, ובנתיב הזה” היא תנאי של אפליקציה חזקה מול צרות proxy.

הופכים את ה-proxy לניתן להגדרה ורושמים את הנתיבכברירת מחדל ללכת אחרי הגדרות ה-OS, לאפשר URL מפורש של proxy או bypass או בלי proxy מהגדרות האפליקציה, ולרשום את המסלול שבאמת היה בשימוש יחד עם ה-account שרץPAC לא נקרא / service / מיוחדהמקרה הרגילברירת מחדל: ללכת אחרי ה-OSסביבה חריגה?מגדירים URL, bypass, או בלי proxyמשתמשים בברירת המחדל של ה-OSרושמים מסלול ו-account

איור 10: מגדירים כשחייבים. תמיד רושמים איזה נתיב היה בשימוש.

10. סיכום

  • הגדרות proxy של Windows מתפצלות לשלושה מקורות — הגדרות WinINET לפי user, הגדרות machine של WinHTTP, ו-environment variables — ואיזו נקראת מוכרעת על ידי האפליקציה (ה-HTTP stack שלה) וה-account שרץ.
  • WinINET הוא לאפליקציות אינטראקטיביות ואינו נתמך לשימוש ב-service; שימוש service הוא עבודת WinHTTP (netsh winhttp). ל-“עובד ידנית ולא כ-service” חושדים קודם בהבדל account.
  • netsh winhttp set proxy הוא static ואינו מטפל ב-PAC, ב-auto-detect או ב-authentication. ברשת שמופעלת ב-PAC צריך להחליט איך יטופלו clients שלא יכולים לקרוא PAC.
  • FindProxyForURL של PAC מחזיר proxy או DIRECT לכל URL. WPAD עובד רק ברשת שיש בה סידור DHCP/DNS.
  • ברירת המחדל של .NET Framework היא Internet Options של ה-account שרץ (ניתנת לדריסה ב-defaultProxy); .NET (Core ואילך) הוא environment variables ואז הגדרות proxy של ה-user. ציון מפורש (HttpClientHandler.Proxy) תמיד בעדיפות הגבוהה ביותר.
  • 407 הוא שגיאת authentication של ה-proxy; באפליקציה שרצה תחת service account הסיבה הטיפוסית היא ש-“default credentials” הופכים לאדם אחר.
  • Proxy של TLS inspection מניח הפצת CA פנימי, והתשובה הנכונה ל-certificate error היא הפצה ל-certificate store, לא כיבוי validation. Traffic עם pinning צריך exclusion.
  • מבודדים באופן מכני בסדר “שחזור → איסוף שלושת מקורות ההגדרות → זיהוי ה-account שרץ → סיווג השגיאה → לוג ה-proxy”. בצד האפליקציה, תכנון ש-“יכול להגדיר את ה-proxy, ורושם את הנתיב שהשתמש בו” הוא המניעה הטובה ביותר.

בפעם הבאה שמייעצים לכם עם “רק האפליקציה העסקית לא מתחברת”, שואלים קודם את זה.

תחת account של מי האפליקציה הזו רצה, ואיזה משלושת מקורות הגדרות ה-proxy היא קוראת?

השאלה האחת הזו משנה מאוד את הכניסה לחקירה.

מאמרים קשורים

תחומי ייעוץ קשורים

KomuraSoft LLC מטפלת בחקירת תקלות תקשורת של Windows apps בסביבות proxy ארגוני, authenticating proxy ו-TLS inspection —‏ “עובד במחשב הפיתוח אבל לא מתקשר ברשת הלקוח”, “אחרי שהפכנו ל-service כבר לא הגיע ל-API החיצוני” — ובייעוץ על תכנון תקשורת של אפליקציות עסקיות שמניח סביבת proxy (שדות הגדרה, timeout, תכנון לוגים). אפשר להתחיל מלהגדיר איך משחזרים את התופעה ואיך אוספים לוגים.

קישורי עיון

  1. Microsoft Learn, WinINet vs. WinHTTP. על ההנחיה להשתמש ב-WinINET אלא אם אתם ב-service או ב-process שצריך impersonation ו-session isolation, ועל טבלת השוואת התכונות שמכסה credential cache, credential prompts, תמיכת services, impersonation, session isolation וכדומה. ↩ ↩2 ↩3 ↩4

  2. Microsoft Learn, netsh winhttp. על התחביר של netsh winhttp show/set/import/reset; proxy-server ו-bypass-list של set proxy; import proxy source=ie; והגדרות proxy מפורטות בצורת JSON (Proxy, ProxyBypass, AutoconfigUrl, AutoDetect) דרך set advproxy. ↩ ↩2 ↩3 ↩4

  3. Microsoft Learn, About WinHTTP. על כך ש-WinHTTP הוא HTTP stack שתוכנן לשימוש service וצד שרת, תומך בהרצה תחת service account וב-impersonation, ואינו משתף cookies, cache, credentials של הדפדפן או Internet Options של ה-user. ↩ ↩2 ↩3

  4. Microsoft Learn, Using a proxy with Delivery Optimization. על כך ש-netsh winhttp set proxy הוא הגדרה static שאינה תומכת ב-auto-detect, ב-URL של PAC או ב-proxy authentication; על תצורת proxy לכל מכשיר להקשרים בלי user מחובר (NetworkProxy CSP, מדיניות Make proxy settings per-machine); ועל traffic עם certificate pinning שנכשל תחת TLS inspection וזקוק ל-exclusion. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10

  5. Microsoft Learn, WinHTTP AutoProxy Support. על כך שסקריפט PAC מכיל פונקציה FindProxyForURL(url, host) שמחשבת רשימת proxy לכל בקשה ומציינת חיבור ישיר בערך החזרה מיוחד, ועל כך ש-API של AutoProxy הישן יותר אינו משלב אוטומטית auto proxy ב-HTTP stack כך שהאפליקציה צריכה לקרוא ל-WinHttpGetProxyForUrl. ↩ ↩2 ↩3

  6. Microsoft Learn, WinHttpGetProxyForUrl function. על כך שזה מימוש של פרוטוקול WPAD, שצריך לקרוא לו לכל URL כי קובץ PAC יכול להחזיר proxy אחר לכל URL, ושהוא תומך גם ב-URL PAC מפורש וגם ב-auto-detect מהרשת. ↩ ↩2

  7. Microsoft Learn, HttpClient.DefaultProxy Property. על כך ש-Windows קורא תחילה את ה-environment variables HTTP_PROXY, HTTPS_PROXY, ALL_PROXY ו-NO_PROXY ואם הם לא מוגדרים את הגדרות ה-proxy של ה-user; ש-Linux מאותחל בלי proxy אם ה-environment variables חסרים; ש-NO_PROXY אינו תומך ב-wildcards ומשתמש בהתאמת subdomain עם נקודה מובילה; ושאפשר לכלול ב-URL של ה-proxy שם משתמש וסיסמה. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  8. Microsoft Learn, Configuring Internet Applications. על כך שאלמנט defaultProxy מגדיר את ה-proxy ברירת המחדל ב-.NET Framework; ש-HttpWebRequest בלי property Proxy משתמש ב-proxy ברירת המחדל; ושהגדרות אינטרנט של המערכת והגדרות קובץ ה-config משולבות עם עדיפות לצד קובץ ה-config. ↩ ↩2 ↩3

  9. Microsoft Learn, defaultProxy element (network settings). על ה-attributes enabled ו-useDefaultCredentials של אלמנט system.net/defaultProxy, האלמנטים הילדים proxy, bypasslist ו-module, על כך שהגדרות ה-proxy של המערכת בשימוש אם האלמנט ריק, ועל תצורה עם HttpClient.DefaultProxy במעבר ל-.NET 6 ואילך. ↩ ↩2 ↩3

  10. Microsoft Learn, Authentication in WinHTTP. על כך ש-status code 407 וכותרת Proxy-Authenticate מוחזרים כאשר נדרש proxy authentication (authentication של השרת הוא 401 ו-WWW-Authenticate); על ההבדל בין Basic authentication ל-schemes מסוג challenge/response כמו Kerberos; ועל כך ש-challenge/response פירושו ששם המשתמש והסיסמה אינם נוסעים ברשת. ↩ ↩2 ↩3

  11. Microsoft Learn, HttpClientHandler.DefaultProxyCredentials Property. על ה-property שמגדיר את ה-credentials המשמשים ל-authentication ל-proxy ברירת המחדל כאשר UseProxy הוא true ו-Proxy הוא null כך שמשתמשים ב-proxy ברירת המחדל של המערכת. ↩ ↩2

  12. Microsoft Learn, WebProxy.Credentials Property. על כך ש-property Credentials הוא ה-credentials שנשלחים ל-proxy בתגובה ל-HTTP 407, ועל ההמלצה בתרחישי client רבים להגדיר UseDefaultCredentials ל-true כדי שישתמשו ב-default credentials של ה-user המחובר. ↩ ↩2

  13. Microsoft Learn, Understanding implications when using network intermediation to decrypt or manipulate Microsoft 365 traffic at the network layer. על כך ש-TLS inspection (SSL decryption) היא תצורה שבה proxy או firewall מפענחים, בודקים ומצפינים מחדש TLS; שהיא יכולה לגרום לתקלה ולהידרדרות ביצועים בשירותים שמניחים TLS מקצה לקצה; ועל ההמלצה להחריג traffic ליעד Microsoft 365 מ-decrypt-and-inspect בשכבת הרשת. ↩ ↩2 ↩3

  14. Microsoft Learn, Make HTTP requests with the HttpClient class. על שתי שיטות התצורה HttpClient.DefaultProxy ו-HttpClientHandler.Proxy; על כך שציון Proxy מנצח את קובץ ה-config ואת הגדרות Local Computer; על תצורת WPAD הטיפוסית של קבלת קובץ PAC (wpad.dat וכדומה) דרך שם ה-DNS wpad או DHCP; ועל שיפוט bypass של יעדים מקומיים לפי שם שטוח, loopback והתאמת domain suffix. ↩ ↩2 ↩3 ↩4

  15. Microsoft Learn, WinHttpOpen function. על משמעות כל ערך dwAccessType. WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY (Windows 8.1 ואילך) מחליט אוטומטית את ה-proxy מהגדרות proxy מערכת/user ומטפל גם ב-failover וב-authentication אוטומטית, ו-WINHTTP_ACCESS_TYPE_DEFAULT_PROXY deprecated מ-8.1 ואילך. ↩

  16. Microsoft Learn, Work with existing on-premises proxy servers. על כך ש-HTTPS יוצא מיוסד בבקשת CONNECT ל-proxy; שהצלחה מחזירה HTTP 200; ושתגובות כמו 407 (נדרש authentication) או 502 מציינות שה-proxy אינו מתיר את התקשורת, ולכן כדאי להמשיך בבידוד עם צוות צד ה-proxy. ↩

מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.

העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.

המאמר קשור ישירות לשירותים הבאים.

שאלות נפוצות

שאלות נפוצות בפניות בנושא המאמר.

הדפדפן מתחבר, ורק האפליקציה העסקית לא עוברת את ה-proxy הארגוני. למה?
הדפדפן קורא את הגדרות ה-proxy ה-per-user של WinINET. אפליקציה עסקית לא בהכרח קוראת את אותן הגדרות. אפליקציה שרצה כ-Windows service, או תחת account אחר, רואה את מה שנראה מאותו account, את הגדרות ה-machine של WinHTTP, או environment variables. קודם מזהים את ה-account שבו זה רץ, ובודקים את הגדרות ה-proxy שנראות ממנו גם ב-netsh winhttp show proxy וגם בהגדרות ה-user. אם אפשר לשחזר עם curl.exe או כלי דומה, באותו account על אותה מכונה, זו אי-התאמה בין מקורות הגדרה ולא באג באפליקציה.
הגדרתי netsh winhttp set proxy, וה-traffic של האפליקציה לא השתנה. למה?
netsh winhttp מגדיר את ברירת המחדל ברמת המכונה של WinHTTP. זה לא משפיע על דפדפנים או אפליקציות אינטראקטיביות שקוראות WinINET, וגם לא על HttpClient ב-.NET (Core ואילך), שמעדיף environment variables. netsh winhttp set proxy הוא גם static: אין שם PAC autoconfig, auto-detect או proxy authentication. קודם מאשרים באיזה HTTP stack האפליקציה משתמשת ומאיזה מקור הגדרות היא פותרת את ה-proxy.
אילו הגדרות proxy אפליקציית .NET קוראת?
.NET Framework משתמש כברירת מחדל בהגדרות Internet Options (מקבילת WinINET) של ה-account שבו זה רץ, ואפשר לדרוס אותן באלמנט system.net/defaultProxy ב-app.config. HttpClient ב-.NET (Core ואילך) קורא קודם environment variables כמו HTTP_PROXY, HTTPS_PROXY ו-NO_PROXY, ואם הם לא מוגדרים נופל להגדרות ה-proxy של ה-user ב-Windows. בשני המקרים HttpClientHandler.Proxy מפורש מנצח. סדר ה-resolution כברירת מחדל שונה בין Framework ל-Core ואילך, ולכן במעבר בודקים מחדש את התנהגות ה-proxy.
מה בודקים כשחוזר 407 Proxy Authentication Required?
407 אומר שה-proxy עצמו דורש authentication. זה לא שגיאת authentication של שרת היעד (401). קודם מאשרים איזו scheme ה-proxy מבקש (Negotiate, NTLM, Basic) מכותרת Proxy-Authenticate, וב-.NET מעבירים credentials עם HttpClientHandler.DefaultProxyCredentials או WebProxy.UseDefaultCredentials. באפליקציה שרצה תחת service account, default credentials הם של ה-service account, ולכן התקרית הטיפוסית היא שזה עובד למשתמש אינטראקטיבי ונופל ל-407 ברגע שהופכים ל-service. בודקים גם בלוג של ה-proxy כמי זה אומת.
Proxy מסוג TLS inspection מייצר certificate errors. מותר לכבות certificate validation?
כיבוי לא מומלץ. Proxy של TLS inspection מפענח את ה-traffic ואז מציג ל-client certificate שנחתם מחדש על ידי ה-CA שלו, ולכן ה-validation נכשל אם ה-CA הזה לא נמצא ב-trusted roots. התיקון הנכון הוא להפיץ את ה-CA הפנימי ל-certificate store של Windows (בדרך כלל Trusted Root Certification Authorities של Local Computer). כיבוי validation בקוד אומר ש-MITM לא יתגלה כשהאפליקציה רצה ברשת חיצונית, והפגיעות נשארת.

פרופיל הכותב

עמוד היכרות עם כותב המאמר.

Go Komura

מנהל KomuraSoft LLC

מתמחה בפיתוח תוכנה עבור Windows, ייעוץ טכני וחקירת תקלות, בעיקר בפרויקטים עם מערכות קיימות ובאגים שקשה לשחזר.

קישורים ציבוריים

חזרה לבלוג