היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 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 variablesHTTP_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 נכונות ועדיין לא מתחבר”; המציאות היא “המקור שהאפליקציה קראה היה מקור אחר מזה שבדקתם”.
flowchart TB
accTitle: שלושה מקורות של הגדרות proxy ב-Windows
accDescr: WinINET הוא הגדרות per-user ו-Internet Options, WinHTTP הוא ברירת מחדל ברמת המכונה דרך netsh, ו-environment variables הם ב-scope של process. איזה מקור נקרא מחליטה האפליקציה, לא צד ההגדרות
fam{"איזה מקור?"}
fam --> wininet["הגדרות WinINET לפי user"]
fam --> winhttp["הגדרות machine של WinHTTP"]
fam --> env["HTTP_PROXY ודומיו"]
wininet -.-> r1["דפדפנים ו-desktop apps"]
winhttp -.-> r2["services וחלק מרכיבי ה-OS"]
env -.-> r3[".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
flowchart TB
accTitle: WinINET לאפליקציות אינטראקטיביות, WinHTTP ל-services
accDescr: WinINET יורש את Internet Options של ה-user המחובר ואינו נתמך ב-service. WinHTTP רץ תחת service account בלי UI ואינו משתף את הגדרות הדפדפן של ה-user
q{"desktop app אינטראקטיבית?"}
q -->|"כן"| ie["WinINET"]
q -->|"service או דמוי-service"| wh["WinHTTP"]
ie -.-> ieNote["קורא Internet Options של ה-user"]
wh -.-> whNote["הגדרות 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
שני אילוצים לזכור כאן.
netsh winhttp set proxyהוא static. הוא לא מטפל ב-auto-detect של proxy, לא בציון URL של PAC, ולא ב-proxy authentication.4import proxy source=ieמעתיק רק את ההגדרות הסטטיות באותו רגע; הוא לא עוקב אחרי שינויים מאוחרים בצד Internet Options. כשצריך תצורה לכל מכונה שכוללת PAC או auto-detect, מגדירים את ההגדרות המפורטות בצורת JSON (Proxy,ProxyBypass,AutoconfigUrl,AutoDetect) עםnetsh winhttp set advproxy.2
3.3. ה-pitfall הנפוץ: service לא קורא את הגדרות ה-IE של ה-user
הדפוס שרואים הכי הרבה בשטח, לפי סדר הזמן, נראה כך.
- מפתח מריץ את הכלי על המחשב שלו → הגדרות ה-proxy ה-per-user (1) נכנסות לתוקף וזה עובד
- בייצור משאירים אותו resident כ-Windows service (איך בונים ומפעילים Windows services) תחת LocalSystem
- ההגדרות שנראות מ-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
flowchart TB
accTitle: למה service לא רואה את הגדרות ה-IE של ה-user
accDescr: הרצה ידנית כ-user קוראת הגדרות WinINET per-user ועובדת. כ-LocalSystem ההגדרות האלה לא נראות. אפליקציית WinHTTP native אז הולכת אחרי הגדרות machine לא מוגדרות (DIRECT). service של .NET Core+ עדיין משתמש ב-environment variables או ב-handler.Proxy מפורש ואינו עובר ל-netsh winhttp
dev["הרצה ידנית כ-user"] --> ok["הגדרות WinINET per-user חלות"]
svc["Windows service כ-LocalSystem"] --> miss["הגדרות per-user לא נראות"]
miss --> stack{"איזה HTTP stack?"}
stack -->|"WinHTTP"| direct["WinHTTP לא מוגדר = DIRECT"]
stack -->|".NET Core+"| env["environment variables או handler.Proxy"]
direct --> fail["ה-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 לבדו ברשת בלי סידור כזה רק מוסיפה זמן המתנה לכישלון הגילוי.
flowchart TB
accTitle: PAC פותר proxy לכל URL, WPAD רק מוצא את ה-PAC
accDescr: FindProxyForURL מקבל URL ו-host ומחזיר רשימת proxy או DIRECT. WPAD מאתר את ה-PAC רק דרך DHCP או DNS. client שאינו יכול להעריך PAC נופל ל-proxy סטטי או ל-environment variables
url["URL הבקשה"] --> pac["FindProxyForURL"]
pac -->|"רשימת proxy"| via["לעבור דרך proxy"]
pac -->|"DIRECT"| dir["להתחבר בלי proxy"]
wpad["WPAD דרך DHCP או DNS"] -.-> pac
nopac["client שאינו מעריך PAC"] -.-> fb["הגדרות סטטיות או 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 |
flowchart TB
accTitle: Proxy resolution ברירת מחדל ב-Framework מול Core ואילך
accDescr: HttpClientHandler.Proxy מפורש תמיד מנצח. Framework אז משתמש ב-app.config defaultProxy וב-Internet Options של ה-account שרץ. Core ואילך משתמש בהשמה ל-HttpClient.DefaultProxy, אחר כך environment variables, אחר כך הגדרות proxy של ה-user ב-Windows
expl["handler.Proxy מפורש"] --> done["ה-proxy הזה בשימוש"]
noexpl["אין Proxy מפורש"] --> fw{"איזה runtime?"}
fw -->|"Framework"| cfg["app.config defaultProxy"]
cfg --> ie["Internet Options של ה-account"]
fw -->|"Core ואילך"| dp["HttpClient.DefaultProxy"]
dp --> ev["HTTP_PROXY ודומיו"]
ev --> user["הגדרות 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
flowchart TB
accTitle: 407 הוא ה-proxy, 401 הוא שרת היעד
accDescr: 407 ו-Proxy-Authenticate באים מה-proxy. 401 ו-WWW-Authenticate באים משרת היעד. ה-credentials והמקום שמגדירים אותם נבדלים
req["בקשה יוצאת"] --> who{"מי דורש authentication?"}
who -->|"ה-proxy"| e407["407 + Proxy-Authenticate"]
who -->|"היעד"| e401["401 + WWW-Authenticate"]
e407 -.-> cred["DefaultProxyCredentials"]
איור 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”.
flowchart TB
accTitle: HTTPS דרך proxy הוא CONNECT tunnel
accDescr: ה-client שולח CONNECT ל-proxy, ה-proxy פותח TCP tunnel ומחזיר 200, ואז ה-client והיעד מבצעים TLS handshake ב-tunnel. לוג ה-proxy רואה את ה-host, לא את נתיב ה-URL
cli["client"] -->|"CONNECT host:443"| px["proxy"]
px -->|"200 ו-TCP tunnel"| dest["יעד"]
dest -->|"TLS ב-tunnel"| cli
px -.-> log["לוג: 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.
flowchart TB
accTitle: Proxy של TLS inspection חותם מחדש את ה-certificate
accDescr: ה-proxy מסיים TLS, בודק את התוכן, ומציג certificate שנחתם מחדש על ידי ה-CA שלו. ה-validation מחזיק רק אם אותו CA ב-trusted roots. לא מכבים validation בקוד
real["server certificate אמיתי"] --> px["proxy של TLS inspection"]
px --> fake["נחתם מחדש על ידי ה-CA של ה-proxy"]
fake --> client["validation של ה-client"]
client -->|"ה-CA ב-trusted roots"| ok["הצלחה"]
client -->|"ה-CA חסר"| err["certificate error"]
err -.-> fix["מפיצים את ה-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).
flowchart TB
accTitle: חמישה צעדים לבידוד כשל proxy
accDescr: משחזרים תחת אותו account, אוספים את שלושת מקורות ההגדרות, מזהים את ה-account שרץ, מסווגים את השגיאה, ואז בודקים את לוג ה-proxy
s1["שחזור עם curl"] --> s2["איסוף שלושה מקורות"]
s2 --> s3["זיהוי ה-account"]
s3 --> s4["סיווג השגיאה"]
s4 --> s5["בדיקת לוג ה-proxy"]
s4 -.-> e407["407: authentication"]
s4 -.-> ecert["certificate error: inspection"]
s4 -.-> eto["timeout: לא הגיע"]
איור 9: הולכים את חמשת הצעדים לפי הסדר. מחלקת השגיאה בוחרת את הפרק הבא.
9. המלצה לתכנון — אפליקציה שאפשר להגדיר עליה את ה-proxy
הופכים את הליך החקירה והוא הופך להנחיית תכנון בצד האפליקציה. ל-Windows app שתספקו לסביבה עם proxy ארגוני, מומלץ כדלקמן.
- הופכים את ה-proxy לניתן להגדרה מהגדרות האפליקציה. ברירת המחדל היא “ללכת אחרי הגדרות ה-OS”. ברוב הסביבות ברירת המחדל מספיקה; רק בסביבות החריגות — אי אפשר לקרוא PAC, רץ כ-service, תצורת proxy מיוחדת — מאפשרים לציין URL של proxy, bypass list, ו-“אל תשתמש ב-proxy” מקובץ הגדרות.
HttpClientHandler.Proxy/UseProxyבסעיף 5.3 הוא נקודת המימוש.14 - כותבים איך יעדים פנימיים (API, databases, שרתי רישוי וכדומה) מטופלים כ-exceptions של proxy. שמים בצורה שאפשר לכתוב בנוהל הפריסה אם הם מוחרגים על ידי PAC DIRECT, bypass list, או
NO_PROXY. כללי ההתאמה שלNO_PROXY(בלי wildcards, מה נקודה מובילה אומרת) מובנים לא נכון בהרחבה, ולכן מצרפים דוגמאות.7 - מתכננים timeout ו-retry בהנחה שעוברים דרך proxy. אם ה-proxy למטה או תקוע ב-authentication, מימוש שמחכה ל-timeout ברירת מחדל ארוך מקפיא גם את ה-UI וגם את ההפעלה. מפרידים connection timeout קצר יותר, ומגבילים retry לבקשות idempotent (פרטי תכנון ב-אל תעטפו HttpClient ב-using).
- רושמים בלוג “איזה 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.
flowchart TB
accTitle: הופכים את ה-proxy לניתן להגדרה ורושמים את הנתיב
accDescr: כברירת מחדל ללכת אחרי הגדרות ה-OS, לאפשר URL מפורש של proxy או bypass או בלי proxy מהגדרות האפליקציה, ולרשום את המסלול שבאמת היה בשימוש יחד עם ה-account שרץ
def["ברירת מחדל: ללכת אחרי ה-OS"] --> exc{"סביבה חריגה?"}
exc -->|"PAC לא נקרא / service / מיוחד"| cfg["מגדירים URL, bypass, או בלי proxy"]
exc -->|"המקרה הרגיל"| os["משתמשים בברירת המחדל של ה-OS"]
cfg --> log["רושמים מסלול ו-account"]
os --> log
איור 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 היא קוראת?
השאלה האחת הזו משנה מאוד את הכניסה לחקירה.
מאמרים קשורים
- אל תעטפו HttpClient ב-using — תקשורת HTTP מעשית באפליקציות עסקיות ב-C# (דפוסי יצירה, timeout, retry)
- Packet capture ב-Windows בפועל — בחירה בין pktmon, netsh trace ו-Wireshark
- Windows Firewall ואפליקציות עסקיות — רושמים inbound rules מה-installer
- איך בונים ומפעילים Windows services — מבחירה בין Task Scheduler ל-services ועד להפיכת BackgroundService ל-Windows service
- NTLM ו-Kerberos מוסברים בתרשימים — למה ה-authentication נופל ל-NTLM
- ה-certificate store של Windows בפועל — user או computer, במה כדאי להשתמש?
תחומי ייעוץ קשורים
KomuraSoft LLC מטפלת בחקירת תקלות תקשורת של Windows apps בסביבות proxy ארגוני, authenticating proxy ו-TLS inspection — “עובד במחשב הפיתוח אבל לא מתקשר ברשת הלקוח”, “אחרי שהפכנו ל-service כבר לא הגיע ל-API החיצוני” — ובייעוץ על תכנון תקשורת של אפליקציות עסקיות שמניח סביבת proxy (שדות הגדרה, timeout, תכנון לוגים). אפשר להתחיל מלהגדיר איך משחזרים את התופעה ואיך אוספים לוגים.
קישורי עיון
-
Microsoft Learn, WinINet vs. WinHTTP. על ההנחיה להשתמש ב-WinINET אלא אם אתם ב-service או ב-process שצריך impersonation ו-session isolation, ועל טבלת השוואת התכונות שמכסה credential cache, credential prompts, תמיכת services, impersonation, session isolation וכדומה. ↩ ↩2 ↩3 ↩4
-
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
-
Microsoft Learn, About WinHTTP. על כך ש-WinHTTP הוא HTTP stack שתוכנן לשימוש service וצד שרת, תומך בהרצה תחת service account וב-impersonation, ואינו משתף cookies, cache, credentials של הדפדפן או Internet Options של ה-user. ↩ ↩2 ↩3
-
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
-
Microsoft Learn, WinHTTP AutoProxy Support. על כך שסקריפט PAC מכיל פונקציה FindProxyForURL(url, host) שמחשבת רשימת proxy לכל בקשה ומציינת חיבור ישיר בערך החזרה מיוחד, ועל כך ש-API של AutoProxy הישן יותר אינו משלב אוטומטית auto proxy ב-HTTP stack כך שהאפליקציה צריכה לקרוא ל-WinHttpGetProxyForUrl. ↩ ↩2 ↩3
-
Microsoft Learn, WinHttpGetProxyForUrl function. על כך שזה מימוש של פרוטוקול WPAD, שצריך לקרוא לו לכל URL כי קובץ PAC יכול להחזיר proxy אחר לכל URL, ושהוא תומך גם ב-URL PAC מפורש וגם ב-auto-detect מהרשת. ↩ ↩2
-
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
-
Microsoft Learn, Configuring Internet Applications. על כך שאלמנט defaultProxy מגדיר את ה-proxy ברירת המחדל ב-.NET Framework; ש-HttpWebRequest בלי property Proxy משתמש ב-proxy ברירת המחדל; ושהגדרות אינטרנט של המערכת והגדרות קובץ ה-config משולבות עם עדיפות לצד קובץ ה-config. ↩ ↩2 ↩3
-
Microsoft Learn, defaultProxy element (network settings). על ה-attributes enabled ו-useDefaultCredentials של אלמנט system.net/defaultProxy, האלמנטים הילדים proxy, bypasslist ו-module, על כך שהגדרות ה-proxy של המערכת בשימוש אם האלמנט ריק, ועל תצורה עם HttpClient.DefaultProxy במעבר ל-.NET 6 ואילך. ↩ ↩2 ↩3
-
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
-
Microsoft Learn, HttpClientHandler.DefaultProxyCredentials Property. על ה-property שמגדיר את ה-credentials המשמשים ל-authentication ל-proxy ברירת המחדל כאשר UseProxy הוא true ו-Proxy הוא null כך שמשתמשים ב-proxy ברירת המחדל של המערכת. ↩ ↩2
-
Microsoft Learn, WebProxy.Credentials Property. על כך ש-property Credentials הוא ה-credentials שנשלחים ל-proxy בתגובה ל-HTTP 407, ועל ההמלצה בתרחישי client רבים להגדיר UseDefaultCredentials ל-true כדי שישתמשו ב-default credentials של ה-user המחובר. ↩ ↩2
-
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
-
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
-
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 ואילך. ↩
-
Microsoft Learn, Work with existing on-premises proxy servers. על כך ש-HTTPS יוצא מיוסד בבקשת CONNECT ל-proxy; שהצלחה מחזירה HTTP 200; ושתגובות כמו 407 (נדרש authentication) או 502 מציינות שה-proxy אינו מתיר את התקשורת, ולכן כדאי להמשיך בבידוד עם צוות צד ה-proxy. ↩
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
הרשת עובדת אבל Windows מציג "אין אינטרנט" — לבודד NCSI, DNS, Proxy ו-VPN ב-Windows
למה Windows מציג "אין אינטרנט" בזמן שהרשת עובדת — נקודת המוצא היא קביעת הקישוריות של NCSI. כאן מפרידים בין DNS, proxy, VPN ו-captive port...
Time Travel Debugging — להקליט ולהריץ אחורה באגים שלא משתחררים באפליקציות ארוכות-ריצה
באג פעם בחודש משאיר ב-crash dump רק את התוצאה. מקליטים ומריצים אחורה את הביצוע עם WinDbg Time Travel Debugging (TTD): TTD.exe, ring buffe...
למה arguments נשברים — כללי command-line arguments ב-Windows
Windows מעביר ל-CreateProcess מחרוזת אחת שהמקבל מפצל. מכסה את כללי CommandLineToArgvW, CRT ו-.NET, ArgumentList, ובניה ב-C++.
סיום התמיכה ב-printer drivers של Windows — איך אפליקציות עסקיות מתכוננות להדפסת דוחות ותוויות
Microsoft מפסיקה בהדרגה printer drivers מסוג v3/v4. מה Windows protected print mode מסיר, ואיך עושים inventory ומכינים הדפסת דוחות ותוויו...
שיטות עבודה מומלצות ל-multithreading בפועל: מהדורת .NET — מה להחליט לפני שמוסיפים threads
כללי תכנון שמונעים מקוד multithreaded ב-.NET/C# לקרוס או להיתקע מדי פעם: להשתמש ב-Task במקום ליצור threads בעצמכם, לצמצם shared mutable s...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
פיתוח יישומי Windows
יישומים עסקיים, חיבור התקנים וכלי תקשורת, מהגדרת הדרישות ועד הפיתוח.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- הדפדפן מתחבר, ורק האפליקציה העסקית לא עוברת את ה-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 לא יתגלה כשהאפליקציה רצה ברשת חיצונית, והפגיעות נשארת.