היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 28 Aug 2026)
- פרסום ראשון
האפליקציה קוראת את קובץ התצורה כשמפעילים מ-File Explorer, אבל Task Scheduler מדווח שהוא “לא נמצא”. הופכים אותה לשירות והיא כבר לא יכולה לעשות decrypt לסיסמה השמורה. הדפדפן על השולחן מחובר, אבל ב-CI הוא חוזר למסך ה-login.
עם בעיה מהסוג הזה, בודקים מי התוכנית רצה כ, ואיך לפני שמסתכלים על הקוד. קבצים והגדרות שקיימים באותו מחשב לא בהכרח ניתנים לשימוש באותו אופן ממשתמש הרצה אחר.
השאלה שהמאמר הזה עונה עליה היא למה אפליקציה נשברת כששום דבר בקוד לא השתנה והיא רק הפכה למשימה מתוזמנת, לשירות או ל-job ב-CI. אם רוצים להתחיל מהתסמין, עוברים לפרק שמתאים בטבלה הבאה.
| תסמין | מה להשוות קודם | איפה לקרוא |
|---|---|---|
| קובץ התצורה או פקודה לא נמצאים | משתמש ההרצה, נתיב AppData בפועל, משתני סביבה של המשתמש | AppData ומשתני סביבה |
| ערך Registry שבטוחים שכתבתם חסר | ה-hive של המשתמש ש-HKCU מצביע אליו | HKCU |
| אפשר לקרוא את הקובץ, אבל אי אפשר לעשות decrypt ל-secret | ה-scope של DPAPI ובעל ה-master key | DPAPI |
| מצב ה-sign-in של הדפדפן לא עובר | משתמש ההרצה, profile, המפתח המוגן ב-DPAPI | profiles של דפדפן |
| credentials או תעודות שמורות לא ניתנים לשימוש | הכספת ו-Certificate Store של חשבון ההרצה, סוג ה-logon של המשימה | Credentials ותעודות |
| כונן Z: נעלם כשרצים כ-administrator | ה-token ו-logon session לפני ואחרי elevation | העלאת UAC |
| רוצים בדיקה מלאה לפני מעבר | התלויות וההגדרה לכל צורת הרצה | רשימת בדיקה לפי צורת הרצה, הליך חקירה |
הנחות המאמר
| פריט | תוכן |
|---|---|
| קהל היעד | מפתחים שהופכים אפליקציות עסקיות לשירותים, למשימות מתוזמנות או ל-jobs ב-CI, ואנשי תפעול שחוקרים בעיות “עובד אצלי” |
| סביבת בסיס | Windows 10/11. קוד האימות רץ ב-PowerShell 5.1 ואילך |
| רמת קושי | בינונית |
1. קודם המסקנות
יחידת הבסיס שמחלקת סביבת הרצה ב-Windows אינה המחשב אלא ה-access token וה-SID, כלומר “מי התהליך רץ כ.” AppData, HKCU, מפתחות DPAPI, profiles של דפדפן ו-credentials שייכים לסביבה של המשתמש הזה.
ההגדרות ומצב ה-sign-in שהכנתם תחת ה-logon האינטראקטיבי שלכם לא עוברים אוטומטית ל-SYSTEM או לחשבון שירות אחר. האזורים לנתונים ברמת המכונה הם ProgramData ו-HKLM, ושיתוף דרכם עדיין דורש לתכנן את הרשאות הגישה.
flowchart TB
accTitle: שני עולמות בתוך אותו מחשב
accDescr: אותו מחשב חולק רק HKLM ו-ProgramData, בעוד העולם של ה-SID שלכם והעולם של SID אחר לכל אחד יש AppData, hive של Registry ומפתחות DPAPI משלו, בלתי נראים זה לזה מעבר לגבול המשתמש
pc["אותו מחשב"] --> shared["משותף: HKLM ו-ProgramData"]
pc --> wa["העולם של ה-SID שלכם"]
pc --> wb["העולם של SID אחר (SYSTEM וכו')"]
wa --> ra["AppData, HKCU, מפתחות DPAPI"]
wb --> rb["AppData אחר, hive אחר, מפתחות אחרים"]
ra -.-|"גבול המשתמש: בלתי נראים זה לזה"| rb
איור 1: באותו מחשב, משתמש הרצה אחר פירושו AppData אחר, Registry אחר ומפתחות אחרים.
עם זאת, אותו SID אינו מבטיח אותה סביבה. בודקים גם את סוג ה-logon של המשימה, את טעינת ה-profile ב-IIS, ואת ההבדל ב-logon session שיוצרת העלאת UAC. elevation בתוך אותו חשבון לא הופך את HKCU או את הכספת למשתמש אחר; מה שחשוב הוא לחשוב בנפרד אילו גבולות משתנים.
שאר המאמר מתקדם בסדר הזה: משתמש ההרצה כהנחה (פרק 2), חמשת הגבולות (פרקים 3 עד 7), הבדיקה לפי צורת הרצה (פרק 8), ותכנון וחקירה (פרק 9).
ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 33, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle
2. הנחה: “מי זה רץ כ” מחליט הכל
2.1 בודקים את ה-SID ואת ה-token, לא את שם המשתמש
המזהה ש-Windows משתמש בו כדי לזהות משתמש אינו שם המשתמש אלא ה-SID (security identifier). תהליך מחזיק access token, וה-token מכיל את ה-SID של משתמש ההרצה. ה-principal הזה הוא נקודת ההתחלה בכל פעם שחושבים על בדיקות ACL של קבצים, על ה-Registry הפיזי מאחורי alias, או על מפתחות הצפנה.
משתמשים ב-whoami /user לבדיקה הראשונה. מאשרים את התוצאה בסביבת ההרצה שבה הבעיה קורה, לא במסוף שלכם.
> whoami /user
USER INFORMATION
----------------
User Name SID
=============== =============================================
desktop\you S-1-5-21-3623811015-3361044348-30300820-1001
C:\Users\you הוא הצורה על הדיסק של ה-user profile הקשור ל-SID הזה. profile מורכב מקבוצת תיקיות כמו AppData ומ-hive ה-Registry של המשתמש NTUSER.DAT. כי הוא מועתק מ-profile ברירת המחדל ב-logon הראשון, profile של משתמש אחר מתחיל ממצב התחלתי שנפרד מהסביבה שהגדרתם.1
flowchart TB
accTitle: מנתיב ההפעלה עד ה-profile
accDescr: בין אם הופעל ב-double-click, ב-Task Scheduler או בשירות או IIS, התהליך מחזיק את ה-SID ב-access token שלו, וקבוצת נתוני ה-user profile הקשורה ל-SID הזה הופכת לסביבת ההרצה שלו
e1["double-click"] --> tok["token של התהליך (SID)"]
e2["Task Scheduler"] --> tok
e3["שירות או IIS"] --> tok
tok --> prof["קבוצת profile הקשורה ל-SID"]
prof -.-> note["SID אחר פירושו profile אחר במצב התחלתי"]
איור 2: הנתיב שבו תהליך מופעל קובע את ה-profile של איזה SID הוא נושא בזמן הריצה.
2.2 לחשבונות שירות יש לכל אחד סביבה משלו
ל-Windows יש חשבונות מובנים שרצים בלי שבן אדם מתחבר. לכל אחד מהם יש סביבת הרצה עצמאית.2
| חשבון | SID | לאן ה-profile וה-Registry מצביעים |
|---|---|---|
| SYSTEM (LocalSystem) | S-1-5-18 |
profile תחת C:\Windows\System32\config\systemprofile. HKCU משויך למשתמש ברירת המחדל3 |
| LocalService | S-1-5-19 |
תחת C:\Windows\ServiceProfiles\LocalService. יש לו subkey משלו תחת HKEY_USERS4 |
| NetworkService | S-1-5-20 |
תחת C:\Windows\ServiceProfiles\NetworkService. כמו LocalService, יש לו profile ו-hive משלו4 |
IIS AppPool\<name> |
S-1-5-82-… |
זהות ייחודית ל-pool. ה-profile לא נטען כברירת מחדל5 |
ההבדל בין נתיבי ההפעלה של double-click, Task Scheduler, שירות ו-IIS הופך להבדל בסביבה של מי בשימוש. לא מניחים שההגדרות, המפתחות וה-credentials שהכנתם תחת ה-logon האינטראקטיבי שלכם קיימים גם ביעד ההרצה הזה.
2.3 שלושה תנאים לבדוק אחרי “אותו משתמש”
| תנאי לבדוק | דוגמה לאיפה ההבדל נראה |
|---|---|
| סוג logon | עם S4U logon של משימה, הסיסמה לא נשמרת, והרשת ו-EFS אינם נגישים6 |
| טעינת profile | ב-IIS, loadUserProfile קובע אם AppData וה-hive של המשתמש זמינים7 |
| logon session ו-elevation | גם עם אותו SID, תהליך elevated עשוי לא לראות את כונני הרשת הממופים89 |
לא עוצרים בבדיקת ה-SID; משתמשים בשלושת אלה כדי לסדר מה שונה גם עם אותו חשבון. משימות מכוסות בפירוט בפרק 8, IIS בפרקים 4 ו-5, ו-elevation בפרק 7.
3. גבול 1: AppData — אותו משתנה סביבה מצביע למקום אחר
התסמין הטיפוסי הוא שקובץ התצורה מפסיק להימצא ברגע שהאפליקציה הופכת למשימה מתוזמנת. פתרון הנתיב לא נכשל; הנתיב עשוי להיות פתור נכון למיקום של משתמש אחר, שבו הקובץ לא קיים.
3.1 החלוקות של AppData ואיך משתמש ההרצה משנה אותן
AppData הוא תיקייה תחת ה-user profile. המטרות שלו מחולקות כך.10
| אזור | מטרה עיקרית |
|---|---|
%APPDATA% (Roaming) |
הגדרות משתמש שצריכות לעקוב אחרי ה-profile כשהוא עושה roam |
%LOCALAPPDATA% (Local) |
נתונים ו-caches מקומיים למכונה |
| AppData\LocalLow | נתונים לתהליכים שרצים ב-integrity level נמוך |
גם כשאותו קוד פותח %APPDATA%, המיקום שהוא מפנה אליו משתנה עם משתמש ההרצה.
| משתמש הרצה | דוגמה לאיפה מחפשים את קובץ התצורה |
|---|---|
| משתמש A | C:\Users\a\AppData\Roaming\MyApp |
| SYSTEM | AppData תחת systemprofile |
הקובץ שמשתמש A שמר לא קיים בצד SYSTEM. שגיאה שאומרת רק שקובץ התצורה חסר לא הופכת את זה לברור, לכן בחקירה מסתכלים על הנתיב בפועל שנפתח, לא על שם משתנה הסביבה.
flowchart TB
accTitle: איך %APPDATA% נפתר תלוי במשתמש
accDescr: גם כשאותו קוד פותח %APPDATA%, הוא נפתר לנתיב תחת C:\Users אם משתמש ההרצה הוא אתם ותחת systemprofile אם הוא SYSTEM, וקובץ התצורה שלכם לא קיים באחרון
code["אותו קוד: פותחים %APPDATA%"] --> q{"משתמש ההרצה?"}
q -->|"אתם"| a["C:\\Users\\you\\AppData\\Roaming"]
q -->|"SYSTEM"| b["AppData תחת systemprofile"]
b -.-> miss["הקובץ ששמתם שם חסר"]
איור 3: משתני סביבה לא משקרים, אבל לאן הם נפתרים תלוי ב-token.
3.2 גם PATH שונה לפי משתמש
משתני סביבה של המערכת משותפים לכל המכונה, אבל משתני סביבה של המשתמש הם לפי משתמש. כשפקודה שהוספתם ל-PATH שלכם לא נמצאת משירות, בודקים גם את ההבדל הזה.
מחליטים על מיקום האחסון לפי מי קורא את הנתונים. הגדרות למשתמש הזה בלבד הולכות תחת AppData; נתונים שמשותפים לכל המשתמשים או לשירותים הולכים תחת %ProgramData%, ולאחרונים מתכננים את ה-ACLs. לדרך בחירה מפורטת, ראו “איך בוחרים איפה אפליקציית Windows שומרת נתונים מקומיים”.
flowchart TB
accTitle: בוחרים את מיקום האחסון לפי הקוראים
accDescr: נתונים שרק המשתמש הזה קורא הולכים ל-AppData או HKCU, נתונים שמשותפים לכל המשתמשים או לשירותים הולכים ל-ProgramData או HKLM, ולאחרונים מצטרף תכנון ACL
q{"מי קורא את הנתונים האלה?"} -->|"רק המשתמש הזה"| f1["AppData, HKCU"]
q -->|"כל המשתמשים, שירותים"| f2["ProgramData, HKLM"]
f1 -.-> w1["שוקלים מחדש אם זה עשוי להפוך לשירות"]
f2 -.-> w2["מתכננים הרשאות כתיבה ו-ACLs"]
איור 4: “אי אפשר לקרוא את זה ברגע שזה הפך לשירות” הוא התוצאה של דילוג על הענף הזה בזמן התכנון.
4. גבול 2: HKCU — “המשתמש הנוכחי” משתנה עם הקורא
התסמין הטיפוסי הוא ששירות לא מוצא את מידע הרישיון ש-installer כתב. גם כשגם הכתיבה וגם הקריאה הלכו למשהו בשם HKCU, הם לא בהכרח אותו hive פיזי.
4.1 HKCU הוא alias ל-hive של המשתמש
HKEY_CURRENT_USER (HKCU) אינו hive עצמאי; הוא alias שמנותב למיקום פיזי לפי המשתמש הקורא. בתהליך משתמש רגיל הוא מצביע למפתח של ה-SID הזה תחת HKEY_USERS. התוכן שלו הוא ה-NTUSER.DAT שנטען ב-logon.1
החריג הוא HKCU\Software\Classes, שהמיקום הפיזי שלו הוא קובץ hive נפרד, UsrClass.dat. הקובץ הזה חי תחת %LOCALAPPDATA%\Microsoft\Windows.11
ה-HKCU של LocalSystem משויך למשתמש ברירת המחדל (HKEY_USERS\.DEFAULT). כש-installer שרץ תחת חשבון administrator כותב ל-HKCU ושירות SYSTEM קורא מ-HKCU, שניהם מפנים למקומות שונים.3
flowchart TB
accTitle: מה ה-alias HKCU באמת
accDescr: כשאפליקציה פותחת HKCU, היא מנותבת למפתח ה-SID שלכם תחת HKEY_USERS בתהליך שלכם ולמפתח משתמש ברירת המחדל בתהליך LocalSystem, כך שהערך שה-installer כתב כבר לא נראה
app["קוד האפליקציה: פותחים HKCU"] --> alias["HKCU הוא alias למפתח האמיתי"]
alias -->|"התהליך שלכם"| ha["ה-SID שלכם תחת HKEY_USERS"]
alias -->|"תהליך SYSTEM"| hd["HKEY_USERS\\.DEFAULT"]
hd -.-> gone["הערך שכתבתם לא קיים"]
איור 5: גם תחת אותו שם HKCU, משתמש אחר פירושו hive אחר נקרא ונכתב.
שמים הגדרות ברמת המכונה ב-HKLM. Microsoft לא ממליצה לגשת ל-HKCU משירות. אם צריך לקרוא הגדרות של משתמש, עושים impersonation למשתמש הזה ואז משתמשים ב-RegOpenCurrentUser.12
4.2 בודקים גם אם ה-profile נטען
מעבר לחשבון ההרצה, גם אם ה-profile נטען יכול להיות הבעיה.
IIS application pools רצים בלי לטעון user profile כברירת מחדל. הפעלת loadUserProfile הופכת את AppData ואת ה-hive תחת ה-profile לזמינים.7 ההגדרה הזו משפיעה גם על איפה נשמרים מפתחות DPAPI ו-ASP.NET Core Data Protection של הפרק הבא.
ההגדרה “Do not store password” של משימה נבדקת בנפרד, כמגבלה של סוג logon. גם עם אותו משתמש שצוין, S4U logon לא יכול להשתמש ברשת או ב-EFS. ההבדלים הקונקרטיים בין תצורות מסוכמים בפרק 8.6
5. גבול 3: DPAPI — ההצפנה נעולה עם “המפתח של המשתמש”
בעוד AppData ו-HKCU הם בעיות של הסתכלות במקום אחר, DPAPI מייצר בעיה שבה אפשר לקרוא את הקובץ אבל אי אפשר לעשות decrypt לתוכן. הפיכת אפליקציה שמשתמשת בסיסמה שמורה לשירות וקבלת CryptographicException היא דוגמה אחת.
5.1 בעל master key אחר פירושו אין decryption
DPAPI (Data Protection API) הוא מתקן ההצפנה ש-Windows מספק לאפליקציות. קריאה ל-CryptProtectData או ל-ProtectedData.Protect של .NET מאפשרת לאפליקציה להגן על נתונים בלי לשאת מפתח הצפנה בקוד שלה עצמה.13
זה לא הופך את המפתח למיותר, עם זאת. DPAPI משתמש ב-master key שמנוהל על ידי מערכת ההפעלה. ב-scope CurrentUser, master key אקראי לפי משתמש מוגן במפתח שנגזר מ-credentials של ה-logon ונשמר תחת ה-profile.14
flowchart TB
accTitle: שרשרת המפתחות של DPAPI
accDescr: ה-master key האקראי של המשתמש מוגן במפתח שנגזר מ-credentials של ה-logon, ה-master key הזה מצפין את ה-secrets של האפליקציה, ו-master key של משתמש אחר לא יכול לעשות decrypt לאותו ciphertext
pwd["credentials של logon"] -->|"מגן דרך מפתח נגזר"| mk["ה-master key שלכם"]
mk -->|"מצפין"| sec["secret של האפליקציה (סיסמה שמורה וכו')"]
mk2["master key של משתמש אחר"] -.->|"לא יכול לעשות decrypt"| sec
mk -.-> loc["נשמר תחת ה-profile"]
איור 6: הנתונים לא מוצפנים ישירות מה-credentials; מפתח שנגזר מה-credentials מגן על ה-master key.
הבא הוא דוגמה מינימלית שבה משתמש A מצפין נתונים, מניח אותם במיקום משותף, ומשתמש אחר מנסה לעשות decrypt. שיתוף מיקום האחסון לא משנה מי יכול לעשות decrypt תחת CurrentUser.
# בסשן של משתמש A: מצפינים ב-scope CurrentUser ושומרים למיקום משותף
Add-Type -AssemblyName System.Security
$bytes = [Text.Encoding]::UTF8.GetBytes("secret")
$enc = [Security.Cryptography.ProtectedData]::Protect($bytes, $null, "CurrentUser")
[Convert]::ToBase64String($enc) | Set-Content C:\ProgramData\demo.bin
# כמשתמש אחר (למשל, אחרי שהפכתם ל-SYSTEM עם PsExec), מנסים לעשות decrypt
$enc = [Convert]::FromBase64String((Get-Content C:\ProgramData\demo.bin))
[Security.Cryptography.ProtectedData]::Unprotect($enc, $null, "CurrentUser")
# → CryptographicException: הנתונים אינם תקפים במצב הנוכחי
5.2 בוחרים את ה-scope ממי אמור להיות מסוגל לעשות decrypt
| Scope | יחידת ה-decrypt | שיקול תכנון |
|---|---|---|
CurrentUser |
ה-master key של המשתמש שהצפין את הנתונים | אי אפשר לעשות decrypt ברגע שעוברים לחשבון הרצה אחר |
LocalMachine |
מפתח משותף לאותה מכונה | כל תהליך באותה מכונה יכול לעשות decrypt, לכן מגבילים מי יכול לקרוא את ה-ciphertext עם ACL על הקובץ |
secret שגם שירות וגם המשתמש האינטראקטיבי קוראים צריך להיות מתוכנן מההתחלה כ-LocalMachine משולב עם ACL על הקובץ, או שהתהליך צריך לרוץ תחת החשבון של מי שהצפין. לא משנים את ה-scope רק כדי שהשגיאת decryption תיעלם; מחליטים מי מורשה לעשות decrypt. במכונות משותפות, גם מודעים לסיכון שהגנה ברמת המכונה רחבה מדי.15
flowchart TB
accTitle: איך בוחרים את ה-scope של DPAPI
accDescr: בוחרים את ה-scope CurrentUser אם רק המשתמש הזה אמור להיות מסוגל לעשות decrypt ואת ה-scope LocalMachine אם כמה principals באותו מחשב צריכים, ומגבילים את הקוראים של האחרון עם ACL על הקובץ
q{"מי אמור להיות מסוגל לעשות decrypt?"} -->|"רק המשתמש הזה"| cu["scope CurrentUser"]
q -->|"כמה principals באותו מחשב"| lm["scope LocalMachine"]
cu -.-> r1["decrypt נכשל כשרצים כמשתמש אחר"]
lm -.-> r2["מגבילים קוראים עם ACL על הקובץ"]
איור 7: בוחרים את ה-scope כהחלטת תכנון על מי עושה decrypt, לא כ”מה שקרה לעבוד”.
5.3 “שינוי” סיסמה ו”איפוס” הם שונים
המפתח ששומר על ה-master key תלוי ב-credentials של ה-logon. כשמשתמשים משנים את הסיסמה שלהם עצמם, ה-master key מוגן מחדש במפתח שנגזר מהסיסמה החדשה, והיכולת לעשות decrypt עוברת.
לעומת זאת, כש-admin מאפס את הסיסמה של חשבון מקומי, ciphertext מהעבר עשוי כבר לא להיות ניתן ל-decrypt. גם עם אותו חשבון, צריך לבדוק איך ה-credentials שונו.14
5.4 בודקים איפה המפתחות נשמרים גם ב-ASP.NET Core
גם קוד שמעולם לא קורא ל-DPAPI ישירות יכול להיות תלוי בגבול הזה. ASP.NET Core Data Protection שומר את ה-key ring שמשמש להגן על cookie authentication ודומים במיקום שתלוי בסביבה.16
| סביבה | לאן המפתחות הולכים והתוצאה |
|---|---|
| user profile זמין | %LOCALAPPDATA%\ASP.NET\DataProtection-Keys. ב-Windows המפתחות מוצפנים ב-DPAPI |
| אין profile זמין, והאפליקציה מתארחת ב-IIS | נופלים ל-Registry של HKLM, עם ACL לחשבון תהליך ה-worker |
| אף אחד לא חל | המפתחות הופכים למפתחות זמניים מקומיים לתהליך. הם אובדים בהפעלה מחדש, ונתונים מוגנים כמו authentication cookies הופכים ללא תקפים |
בודקים את loadUserProfile, setProfileEnvironment ואת מודל האירוח כקבוצה, ומבינים איזו תצורה קובעת איפה המפתחות מונחים. מה שחשוב אינו רק שהאפליקציה עולה, אלא אם היא יכולה להשתמש באותם מפתחות אחרי הפעלה מחדש.
בחירת scope ומתי להשתמש ב-Credential Manager במקום מכוסים בפירוט ב-“Secrets ביישומי Windows: DPAPI במקום plaintext ב-config”.
6. גבול 4: profiles של דפדפן — “מחובר” שייך למשתמש
מחוברים על השולחן, אבל כש-CI מפעיל את הדפדפן הוא חוזר למסך ה-login. הבעיה הזו הופכת לניתנת לטיפול ברגע שמפרידים איפה ה-profile נשמר ממפתח ההצפנה.
6.1 יש שני גבולות: מיקום אחסון ומפתח
ה-profile של דפדפן מבוסס Chromium כמו Chrome או Edge חי כברירת מחדל בתיקיית User Data תחת %LOCALAPPDATA%. היסטוריה, cookies, הרחבות, סיסמאות שמורות וכן הלאה שייכים לסביבה של משתמש Windows הזה.17
cookies וסיסמאות שמורות מוצפנים במפתח הצפנה בתוך ה-profile, והמפתח עצמו מוגן ב-DPAPI. העתקת התיקייה למשתמש אחר או למכונה אחרת לכן נכשלת ב-decrypt כי המפתח לא תואם.
Chrome האחרון מניח App-Bound Encryption מעל זה. decrypt של המפתח עובר דרך שירות שרץ עם הרשאות SYSTEM, שמאמת לא רק את המשתמש אלא גם את זהות האפליקציה המבקשת.18 זה חל על דפדפנים מבוססי Chromium; המצב שונה לדפדפנים כמו Firefox שיש להם הגנת profile משלהם.
| גבול | מה קורה ביעד האוטומציה |
|---|---|
| גבול AppData | למשתמש של סוכן CI או של שירות אין את ה-profile שאתם משתמשים בו בדרך כלל |
| גבול DPAPI | גם אם התיקייה מועתקת, אי אפשר לעשות decrypt למפתח המוגן |
flowchart TB
accTitle: שני הגבולות מאחורי מצב sign-in של דפדפן
accDescr: ה-profile של הדפדפן חי תחת LOCALAPPDATA ושייך לגבול 1, ומפתח הצפנת ה-cookie מוגן ב-DPAPI ושייך לגבול 3, כך שגם ה-profile וגם המפתח לא עוברים למשתמש אחר
prof["profile של דפדפן"] --> loc["נשמר תחת LOCALAPPDATA"]
prof --> key["מפתח הצפנת cookie מוגן ב-DPAPI"]
loc -.-> ci["משתמש ההרצה של CI מקבל profile ריק ונפרד"]
key -.-> copy["אי אפשר לקחת בהעתקת התיקייה"]
איור 8: “לקחת את מצב ה-sign-in איתכם” נחסם גם על ידי גבול 1 וגם על ידי גבול 3.
6.2 באוטומציה, הופכים את הדרך שבה מצב sign-in נוצר למפורשת
Selenium ו-Playwright מופעלים כברירת מחדל עם profile זמני חד-פעמי. כך שגם תחת אותו משתמש, מצב ה-sign-in של הדפדפן היומיומי שלכם לא בשימוש אוטומטית.
גם אם מציינים תיקיית profile קבועה, בעיות מיקום האחסון והמפתח של הפרק הקודם נשארות ברגע שעוברים ל-job ב-CI או לשירות תחת משתמש אחר. התיקון אינו להעתיק profile מחובר אלא אחד מאלה.
- מקודדים את שלבי ה-sign-in לחשבון בדיקה.
- משתמשים במנגנון storage-state של כלי האוטומציה כדי לשמור ולשחזר cookies ודומים במפורש.
זה שמשתמש אחר לא יכול להשתמש ב-cookies עם העתקה בלבד אינו אי-נוחות; זה גם גבול אבטחה. מתכננים את האוטומציה על ההנחה שהגבול הזה קיים.
7. גבול 5: Credentials ותעודות — לכל משתמש יש כספת נפרדת
credentials שנשמרו עם cmdkey לא בשימוש כשהמשימה רצה, והאימות נכשל. גם כאן, בודקים לא “זה נשמר במחשב” אלא “כאיזה משתמש זה נשמר.”
7.1 Credential Manager הוא כספת לפי משתמש הרצה
Credential Manager, שאפשר לבדוק עם cmdkey /list, הוא כספת לפי משתמש.19 credentials שמורים נמצאים על הדיסק, אבל הם מוגנים ב-DPAPI ומשמשים תוכניות שרצות כמשתמש הזה.20
הכספת מחזיקה credentials שמורים לשרתי קבצים ולכונני רשת, tokens של Git ששמר git-credential-manager, סיסמאות שמורות לחיבורי RDP, secrets של אפליקציות שמשתמשות ב-Credential API, וכן הלאה.
להיות בכספת של ה-logon האינטראקטיבי שלכם לא שם אותם בכספת של החשבון שמריץ את השירות או המשימה. מכינים שלב הגדרה שמכניס את ה-credentials הנדרשים בהקשר של חשבון ההרצה עצמו. כשרק ה-git pull על השולחן שלכם מצליח, בודקים גם את ההבדל בכספות.
עם זאת, משימה שמוגדרת עם S4U לא מתוקנת בהכנסת credentials בלבד. קודם בודקים את סוג ה-logon, ושוקלים תצורה ששומרת את הסיסמה או מעבר לחשבון שירות. סדר הצעדים מונח בפרק 8.
flowchart TB
accTitle: כספת ה-credentials היא לפי משתמש
accDescr: הכספת שלכם מחזיקה credentials של Git, credentials שמורים לשרתי קבצים וסיסמאות RDP, אבל הכספת של משתמש הרצת השירות ריקה אלא אם מכניסים credentials, וזה מה ששגיאת האימות באמת
you["הכספת שלכם"] --> g["credentials של Git"]
you --> n["credentials שמורים לשרתי קבצים"]
you --> r["סיסמאות RDP שמורות"]
svc["כספת משתמש הרצת השירות"] -.-> empty["ריקה אלא אם הוכנסו = שגיאת האימות האמיתית"]
איור 9: “האימות עובד אצלי” הוא רק קיצור ל”הכספת שלי זמינה.”
7.2 לתעודות, בודקים את ה-store ואת הרשאות המפתח הפרטי בנפרד
| Store | גבול ומטרה |
|---|---|
Cert:\CurrentUser |
store לפי משתמש. המפתח הפרטי של תעודת לקוח שמונחת כאן מוגן לפי משתמש |
Cert:\LocalMachine |
store ברמת המכונה. שמים כאן תעודות לשירותים, ונותנים לחשבון השירות גישת קריאה דרך ה-ACL של המפתח הפרטי |
לתעודה שמשמשת שירות, התכנון הבסיסי הוא store של LocalMachine יחד עם ה-ACL על המפתח הפרטי.21 ה-store של המשתמש חי פיזית תחת HKCU\Software\Microsoft\SystemCertificates, כך שהוא יושב בתוך גבול HKCU.22
לפרטים, ראו “Certificate Store ב-Windows — CurrentUser או LocalMachine, לאן שמים”.
7.3 עם העלאת UAC, מפרידים “אותו חשבון” מ”חשבון אחר”
כשמשתמש administrator מתחבר עם UAC מופעל, נוצרים שני tokens מקושרים: token סטנדרטי עם הרשאות מוגבלות ו-token administrator מלא.8
mappings של כונני רשת הם לפי logon session. Z: עשוי להיות נראה ב-File Explorer ועדיין בלתי נראה לכלי שרץ כ-administrator.9
| איך זה רץ | מה משתנה ומה לא |
|---|---|
| העלאת UAC תוך הישארות באותו חשבון | ה-SID זהה, ו-HKCU וכספת ה-credentials נשארים זהים. mappings של כוננים, שהם לפי logon session, עשויים להפוך לבלתי נראים |
| elevation או RunAs עם ה-credentials של חשבון administrator אחר | גם ה-SID משתנה. HKCU והכספת הופכים לאלה של ה-administrator הזה. גם AppData, מפתחות ומצב דפדפן כפופים לגבול של המשתמש האחר |
לא מניחים שכל “זה מפסיק לעבוד כשעושים elevate” הוא שינוי משתמש; קודם בודקים אם זה אותו חשבון.
flowchart TB
accTitle: הפיצול בתוך משתמש אחד שיוצרת העלאת UAC
accDescr: logon של administrator עם UAC מופעל יוצר שני tokens, token סטנדרטי ו-token elevated, וכונן רשת שממופה בצד ה-token הסטנדרטי אינו נראה לתהליך שרץ עם ה-token ה-elevated
logon["logon של משתמש administrator"] --> t1["token סטנדרטי"]
logon --> t2["token elevated"]
t1 --> d1["כונן Z: ממופה כאן"]
t2 -.->|"logon session נפרד"| d2["כלי elevated לא רואה את Z:"]
איור 10: elevation יוצר “עולם אחר לאותו משתמש.” הגבול אינו רק על ה-SID.
8. רשימת בדיקה לפי צורת הרצה
8.1 למשימות, מסתכלים על סוג ה-logon אחרי חשבון ההרצה
ב-Task Scheduler, מה זמין משתנה עם סוג ה-logon גם כשאותו משתמש צוין.6
| סוג logon | מה לבדוק |
|---|---|
| Interactive token (InteractiveToken) | תצורה שרצה בסשן שמחובר |
| Stored password (Password) | תצורה שיכולה להשתמש ב-credentials גם כשלא אינטראקטיבית |
| S4U (סיסמה לא נשמרת) | הסיסמה לא נשמרת, ומשאבי רשת וקבצים מוצפנים (EFS) אינם נגישים |
כשמשימה לא יכולה להשתמש ב-credentials שמורים, קודם בודקים את מגבלת S4U. לא הופכים הוספת credentials לכספת תוך הישארות על S4U לתיקון שלכם. שוקלים תצורה ששומרת את הסיסמה או מעבר לחשבון שירות, ורק אז, אם עדיין נחוץ, מכניסים credentials לכספת של חשבון ההרצה.
פרטי ההגדרות מכוסים ב-“כשמשימות Task Scheduler לא רצות או יוצאות עם 0x1”.
flowchart TB
accTitle: סוג ה-logon של משימה כציר שני
accDescr: לתצורת הרצה של Task Scheduler יש סוג logon של interactive token, stored password או S4U, ועם S4U הסיסמה לא נשמרת והרשת ו-EFS אינם נגישים
task["תצורת הרצת משימה"] --> lt{"סוג logon"}
lt -->|"Interactive token"| it["רץ בסשן המחובר"]
lt -->|"Stored password"| pw["credentials שמישים גם לא-אינטראקטיבית"]
lt -->|"S4U (סיסמה לא נשמרת)"| s4u["לא מגיעים לרשת או ל-EFS"]
איור 11: גם עם אותו משתמש הרצה, איך הוא התחבר משנה מה זמין.
8.2 טבלת הבדיקה לפני שינוי יעד ההרצה
| צורת הרצה | principal ההרצה | גבולות ותסמינים לבדוק במיוחד |
|---|---|---|
| Task Scheduler | החשבון שצוין ברישום | גבולות 1, 2, 3 ו-5. בודקים לאן AppData ו-HKCU מצביעים, decryption של DPAPI, והכספת. עם S4U, הרשת ו-EFS אינם בשימוש |
| Windows service | SYSTEM, LocalService, NetworkService, חשבון שירות | גבולות 1 עד 5. SYSTEM משתמש ב-systemprofile וב-HKCU של משתמש ברירת המחדל; LocalService ו-NetworkService משתמשים בסביבות שלהם תחת ServiceProfiles. המפתחות, הכספת ומצב הדפדפן של המפתח לא עוברים |
| IIS application pool | זהות ייחודית ל-pool כמו IIS AppPool\<name> |
גבולות 1, 2, 3 ו-5. בודקים שה-profile לא נטען כברירת מחדל, איפה מפתחות Data Protection מונחים, וגישה למפתחות הפרטיים של תעודות CurrentUser |
| RunAs / העלאת UAC | המשתמש שצוין, או token אחר של אותו משתמש | עם אותו חשבון, ה-SID, HKCU והכספת זהים, ו-mappings של כוננים מושפעים מהבדל הסשן. עם חשבון אחר, בודקים את כל גבולות 1 עד 5 |
| סוכן CI/CD | משתמש השירות של הסוכן. לעתים קרובות מעולם לא התחבר אינטראקטיבית | גבולות 1 עד 5. בודקים תלויות ב-profile ובמצב sign-in של הדפדפן, credentials של Git, הגדרות HKCU של המפתח, ונתונים מוגנים ב-DPAPI |
| RDP / שרת משותף | כמה סשנים של אותו משתמש, או כמה משתמשים | כמה סשנים של אותו משתמש חולקים AppData ו-HKCU, לכן שומרים על כתיבות מתנגשות. משתמשים שונים מופרדים בגבולות 1 עד 5 |
השורה האחרונה היא זהירות בכיוון ההפוך. כמה סשני RDP של אותו משתמש לא נותנים לכל סשן AppData ו-HKCU עצמאיים משלו. כאן הבעיה אינה שמשהו בלתי נראה, אלא שאותו דבר משותף ונכתב אליו.
9. הנחיות לתכנון ולחקירה
9.1 מחליטים על מיקומי אחסון והגדרה מה-principal שמשתמש בהם
| יעד | יסודות תכנון |
|---|---|
| הגדרות ייחודיות למשתמש | שמים אותן ב-AppData או ב-HKCU |
| נתונים והגדרות שמשותפים לכל המשתמשים או לשירותים | שמים אותם ב-ProgramData או ב-HKLM, ומתכננים הרשאות כתיבה ו-ACLs |
| Secrets | בוחרים את ה-scope של DPAPI ממי אמור להיות מסוגל לעשות decrypt. עם LocalMachine, מתכננים גם את ה-ACL על הקובץ |
| Credentials ותעודות לשירותים | כוללים הכנסת credentials לכספת של חשבון ההרצה, הנחת התעודה ב-Certificate Store של LocalMachine, והגדרת ה-ACL של המפתח הפרטי בהליך ההגדרה |
אם מתכננים להפוך את האפליקציה לשירות אחר כך, כוללים את principal ההרצה הזה בין הקוראים בשלב שבו מחליטים איפה לשמור דברים. העיקרון הוא לא לשאת תלות ב”מה שקרה להיות בסביבת המפתח” לתפעול.
9.2 חוקרים מ-principal ההרצה למיקום המופנה בפועל
flowchart TB
accTitle: הליך חקירה לתקלות גבול משתמש
accDescr: מאשרים את משתמש ההרצה עם whoami, מסתכלים על ה-token ב-Process Explorer, מזהים את הנתיבים ואת מפתחות ה-Registry שנקראו בפועל עם Process Monitor, ואם צריך משחזרים מהעולם של הצד השני עם psexec
s1["מאשרים את משתמש ההרצה עם whoami /all"] --> s2["בודקים את ה-token ב-Process Explorer"]
s2 --> s3["מזהים את הנתיבים והמפתחות בפועל עם ProcMon"]
s3 --> s4["משחזרים מהעולם של הצד השני עם psexec"]
s3 -.-> hint["נתיב profile לא צפוי הוא הרמז"]
איור 12: מאשרים את משתמש ההרצה, מסתכלים על הנתיבים ועל מפתחות ה-Registry בפועל, ואז משחזרים כ-principal ההרצה היעד.
| שלב | איך בודקים | על מה מסתכלים |
|---|---|---|
| 1. מאשרים את משתמש ההרצה | כותבים whoami /all ללוג מיד אחרי ההפעלה |
האם principal ההרצה של המשימה או השירות שנכשלים זהה לזה שעל השולחן |
| 2. בודקים את ה-token | Process Explorer | המשתמש והסשן של התהליך. זה משתמש אחר, או הקשר הרצה אחר של אותו משתמש? |
| 3. מסתכלים על המיקום המופנה בפועל | Process Monitor | הנתיבים של הקבצים שנפתחו ומפתחות ה-Registry. האם profile אחר מהצפוי מופיע ב-PATH NOT FOUND? |
| 4. משחזרים כ-principal ההרצה היעד | ל-SYSTEM, psexec -s -i cmd |
מנסים את אותה פעולה מ-shell של SYSTEM ומאשרים את ההבדלים מהסביבה האינטראקטיבית שלכם |
כשהגדרות חסרות, חוזרים ל-AppData ול-HKCU; כשאפשר לקרוא את הקובץ אבל לא לעשות decrypt, ל-DPAPI; כשרק האימות נכשל, לכספת, לתעודות ולסוג ה-logon. לא שופטים מהודעת השגיאה לבדה; הקיצור הוא ליישר “מי השתמש באיזה מיקום, עם איזה מפתח או credentials.”
10. סיכום
“עובד אצלי” פירושו “עובד כמשתמש הזה, עם ה-profile הזה, עם המפתחות האלה ועם הכספת הזו.” גם כשאותו .exe מופעל באותו מחשב, הפיכה למשימה, לשירות או ל-job ב-CI צריכה להיות מטופלת כמעבר של סביבת ההרצה.
AppData ומשתני סביבה של המשתמש מפנים ל-profile של משתמש ההרצה, ו-HKCU באותו אופן מצביע ל-hive של המשתמש הזה. ה-scope CurrentUser של DPAPI תלוי ב-master key של המשתמש, וגם מצב sign-in של דפדפן ו-Credential Manager מושפעים מהגבול הזה.
יתר על כן, גם עם אותו SID, ההבדלים בסוג logon, בטעינת profile ובסשן שיוצרת העלאת UAC נשארים. ולהפך, כשכמה סשנים של אותו משתמש חולקים AppData ו-HKCU, חושבים על כתיבות מתנגשות.
בסקירות תכנון, שואלים את השאלה הבאה.
האם הקוד הזה נכון לא משנה כאיזה משתמש הוא רץ?
מספקים את מיקומי האחסון, המפתחות וה-credentials הנדרשים במפורש ל-principal ההרצה בפועל. מאשרים את העיקרון הזה לפני המעבר, ואפשר לצמצם, בשלב התכנון, את השבירה שבה “הקוד לא השתנה, ובכל זאת זה נשבר.”
מאמרים קשורים
- Secrets ביישומי Windows: DPAPI במקום plaintext ב-config
- איך בוחרים איפה אפליקציית Windows שומרת נתונים מקומיים — טבלת החלטה ל-SQLite / JSON / Registry / Access
- כשמשימות Task Scheduler לא רצות או יוצאות עם 0x1 — בידוד הסיבה ותכנון תפעול אמין
- חשבונות שירות ב-Windows: LocalSystem, virtual accounts ו-gMSA
- Certificate Store ב-Windows — CurrentUser או LocalMachine, לאן שמים
תחומי ייעוץ קשורים
KomuraSoft LLC מטפלת בתכנון סביבות הרצה כשאפליקציות עסקיות הופכות לשירותים או למשימות מתוזמנות, בחקירת כשלים של “עובד אצלי”, ובתכנון ניהול secrets לאפליקציות Windows.
- Windows Custom Software Development
- חקירת תקלות ואיתור גורמים
- שימוש חוזר בנכסים קיימים והעברתם
- יצירת קשר
קישורים
-
Microsoft Learn, About User Profiles. על כך ש-user profile נוצר ב-logon הראשון, ועל כך ש-profile מורכב מ-hive ה-Registry NTUSER.DAT (נטען ב-logon וממופה ל-HKEY_CURRENT_USER) ומקבוצת תיקיות ה-profile במערכת הקבצים. ↩ ↩2
-
Microsoft Learn, Local accounts. על כך ש-SYSTEM (S-1-5-18), NETWORK SERVICE (S-1-5-20) ו-LOCAL SERVICE (S-1-5-19) הם חשבונות המערכת המקומיים כברירת מחדל שמשמשים להרצת מערכת ההפעלה והשירותים. ↩
-
Microsoft Learn, LocalSystem Account. על כך שה-token של LocalSystem כולל NT AUTHORITY\SYSTEM, על כך שהוא לא משויך לשום חשבון משתמש מחובר, וכתוצאה על כך ש-HKEY_CURRENT_USER משויך למשתמש ברירת המחדל ועל הצורך לעשות impersonation למשתמש כדי לגשת ל-profile של המשתמש הזה. ↩ ↩2
-
Microsoft Learn, LocalService Account. על כך שלחשבון LocalService יש subkey משלו תחת HKEY_USERS, ועל כך ש-HKEY_CURRENT_USER משויך לחשבון LocalService. אותו דבר חל על NetworkService (NetworkService Account). ↩ ↩2
-
Microsoft Learn, Application Pool Identities. על כך ש-application pools רצים תחת זהות ייחודית ל-pool, על כך ש-IIS לא טוען את ה-user profile של Windows כברירת מחדל, ועל הגדרת מאפיין LoadUserProfile ל-true כדי לטעון את ה-profile. ↩
-
Microsoft Learn, logonType Simple Type. על כך שסוגי logon של משימות כוללים S4U, Password ו-InteractiveToken, ועל כך ש-S4U logon לא שומר את הסיסמה ואין לו גישה לרשת או לקבצים מוצפנים. ↩ ↩2 ↩3
-
Microsoft Learn, Process Model Settings for an Application Pool. על המאפיינים loadUserProfile ו-setProfileEnvironment של processModel של application pool, ששולטים אם תהליך ה-worker טוען את ה-user profile. ↩ ↩2
-
Microsoft Learn, How User Account Control works. על כך ש-logon של משתמש administrator יוצר שני tokens מקושרים, token משתמש סטנדרטי ו-access token administrator מלא, כש-UAC מופעל. ↩ ↩2
-
Microsoft Learn, Mapped drives are not available from an elevated prompt. על כך שכונני רשת שממופים בסשן שהתחבר עם ה-token הסטנדרטי אינם זמינים לתהליכים elevated, ועל הסיבה הבסיסית ששני ה-logon sessions המקושרים מחזיקים את mappings הכוננים שלהם בנפרד. ↩ ↩2
-
Microsoft Learn, KNOWNFOLDERID. על כך ש-FOLDERID_RoamingAppData (%APPDATA%), FOLDERID_LocalAppData (%LOCALAPPDATA%) ו-FOLDERID_LocalAppDataLow מוגדרים כ-known folders לפי משתמש. ↩
-
Microsoft Learn, Error occurs during desktop setup and desktop location is unavailable. על כך של-user profile יש שני קבצי hive, NTUSER.DAT ו-UsrClass.dat, ועל כך ש-UsrClass.dat מונח תחת AppData\Local\Microsoft\Windows. ↩
-
Microsoft Learn, Services and the Registry. על כך ששירותים לא ניגשים ל-HKEY_CURRENT_USER או ל-HKEY_CLASSES_ROOT, ועל שימוש בפונקציה RegOpenCurrentUser כשעושים impersonation למשתמש. ↩
-
Microsoft Learn, CryptProtectData function. על כך ש-CryptProtectData בדרך כלל מגן על נתונים במפתח סשן שמשויך למשתמש המחובר ומניח decrypt על ידי אותו משתמש, ועל כך שהדגל CRYPTPROTECT_LOCAL_MACHINE עובר להגנה ברמת המכונה. ↩
-
Microsoft Learn, Windows Data Protection. על כך ש-DPAPI מגן על master key אקראי בהצפנתו במפתח שנגזר מסיסמת המשתמש, על כך שה-master key נשמר תחת ה-user profile, ועל כך שה-master key מוגן מחדש כשהסיסמה משתנה. ↩ ↩2
-
Microsoft Learn, ProtectedData Class. על כך ש-DataProtectionScope.CurrentUser מאפשר decrypt רק למשתמש שהגן על הנתונים, ועל כך ש-LocalMachine מאפשר decrypt לכל תהליך באותה מכונה. ↩
-
Microsoft Learn, Data Protection key management and lifetime in ASP.NET Core. על כך שהמפתחות נשמרים ב-%LOCALAPPDATA%\ASP.NET\DataProtection-Keys ומוצפנים ב-DPAPI ב-Windows כש-user profile זמין, על הנפילה ל-Registry של HKLM עם ACL לחשבון תהליך ה-worker כשמתארחים ב-IIS בלי profile, על כך שהמפתחות אובדים כשהתהליך יוצא ו-payloads מוגנים הופכים לבלתי ניתנים ל-decrypt כשאף אחד מהתנאים לא חל, ועל המעורבות של מאפיין setProfileEnvironment. ↩
-
פרויקט Chromium, User Data Directory. על כך שתיקיית User Data כברירת מחדל של Chrome ב-Windows היא %LOCALAPPDATA%\Google\Chrome\User Data, ועל כך ש-profiles (היסטוריה, סימניות, cookies וכן הלאה) מונחים תחתיה. ↩
-
Google Security Blog, Improving the security of Chrome cookies on Windows. על כך ש-Chrome השתמש ב-DPAPI כדי להצפין cookies ודומים ב-Windows, ועל כך ש-App-Bound Encryption מגן על המפתח דרך שירות שרץ עם הרשאות SYSTEM ומאמת את זהות האפליקציה שמבקשת decrypt. ↩
-
Microsoft Learn, cmdkey. על כך שפקודת cmdkey מציגה, יוצרת ומוחקת שמות משתמש וסיסמאות שמורים (credentials). ↩
-
Microsoft Learn, Cached and Stored Credentials Technical Overview. על כך ש-credentials שנשמרו ב-Credential Manager נשמרים על הדיסק ומוגנים ב-DPAPI, ועל כך שתוכניות שרצות כמשתמש הזה יכולות לגשת ל-credentials ב-store הזה. ↩
-
Microsoft Learn, Local Machine and Current User Certificate Stores. על כך שיש שני סוגים של Certificate Stores, ה-store של המכונה המקומית (ברמת המכונה) וה-store של המשתמש הנוכחי (לפי משתמש). ↩
-
Microsoft Learn, System Store Locations. על כך שה-system store CERT_SYSTEM_STORE_CURRENT_USER מונח תחת HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates ב-Registry. ↩
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
User profile ב-Windows: AppData ו-NTUSER.DAT
יסודות ה-user profile ב-Windows: איך מחלקים AppData, local / roaming / Mandatory / Temporary, Folder Redirection, FSLogix, ומאיפה בודקים ...
למה תיקייה משותפת ב-Windows עובדת לפעמים ונכשלת בפעמים אחרות — troubleshooting של Kerberos, NTLM ו-Credentials
מאבחנים גישה לסירוגין לתיקייה משותפת ב-Windows לפי תסמינים ולוגים. בודקים שמות מול כתובות IP, כשלים רק באפליקציה, סיסמאות ריקות, שגיאה 12...
אותו 1 GB, ובכל זאת תיקיית תמונות מועתקת לאט יותר מסרטון אחד — למה?
למה נתונים באותו גודל מועתקים במהירויות שונות ב-Windows: מספר קבצים, latency של SSD ו-NAS, איגוד ב-ZIP, השוואת יצירה-העברה-חילוץ, ו-roboc...
מה זה Hardware-Accelerated GPU Scheduling ב-Windows — האם On מאיץ את המחשב?
מדריך מאויר למשתמשים כלליים על Hardware-accelerated GPU scheduling (HAGS) ב-Windows: איך זה עובד, מתי להדליק או לכבות, למה ההגדרה לא מופי...
סדר name resolution ב-Windows — hosts, DNS cache, LLMNR/mDNS ו-DoH
האם hosts, ה-DNS cache, שרת DNS או LLMNR/mDNS ענו קובע למה חלק מהמחשבים נכשלים. לומדים את סדר name resolution ב-Windows, מה DoH משנה, ואי...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
פיתוח יישומי Windows
יישומים עסקיים, חיבור התקנים וכלי תקשורת, מהגדרת הדרישות ועד הפיתוח.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- אפליקציה שעובדת כשמפעילים מ-File Explorer לא מוצאת את קובץ התצורה כשמפעילים מ-Task Scheduler. למה?
- כי משתני סביבה כמו %APPDATA% נפתרים ל-profile של המשתמש שמריץ את התוכנית. כשהמשימה רצה כ-SYSTEM או כחשבון אחר, משתני הסביבה מצביעים ל-profile אחר (תחת systemprofile במקרה של SYSTEM), וקובץ התצורה ששמרתם לא קיים שם. בודקים את החשבון שהמשימה רצה כ, ושמים נתונים שצריכים להיות משותפים תחת ProgramData כתיקון הקבוע.
- סיסמה שנשמרה עם ProtectedData.Protect כבר לא ניתנת ל-decrypt ברגע שהאפליקציה הפכה לשירות.
- DPAPI ב-scope CurrentUser תלוי ב-master key של המשתמש שהצפין את הנתונים. אם השירות רץ כחשבון אחר, ה-master key הוא אחר, ולכן decryption נכשל עם CryptographicException. מתכננים מחדש secret שגם השירות וגם המשתמש האינטראקטיבי קוראים כך שישתמש ב-scope LocalMachine יחד עם ACL על הקובץ, או מריצים את השירות תחת החשבון של מי שהצפין.
- מה קורה כשתהליך שרץ כ-SYSTEM קורא HKCU?
- בתהליך LocalSystem, HKEY_CURRENT_USER משויך למשתמש ברירת המחדל (HKEY_USERS\.DEFAULT), כך שהערכים שהמשתמש האינטראקטיבי כתב ל-HKCU אינם נראים. שמים הגדרות ברמת המכונה ב-HKLM, ואם חייבים לקרוא הגדרות של משתמש, עושים impersonation למשתמש הזה ואז משתמשים ב-RegOpenCurrentUser.
- אפשר להעתיק profile מחובר של Chrome/Edge למכונת CI ולהשתמש בו?
- בדרך כלל לא. ה-profile של דפדפן מבוסס Chromium כמו Chrome או Edge חי תחת %LOCALAPPDATA% של המשתמש, ומפתח ההצפנה של cookies ושל סיסמאות שמורות מוגן ב-DPAPI של המשתמש הזה. העתקת התיקייה למשתמש אחר או למכונה אחרת נכשלת ב-decrypt כי המפתח לא תואם (דפדפנים כמו Firefox, שיש להם הגנת profile משלהם, הם סיפור אחר). לאוטומציה, מקודדים את שלבי ה-sign-in לחשבון בדיקה, או משתמשים במנגנון storage-state של כלי האוטומציה.
- Credentials שנשמרו עם cmdkey לא בשימוש כשהמשימה רצה מ-Task Scheduler.
- כי כספת Credential Manager נפרדת לכל משתמש, ומה ששמרתם נכנס לכספת של ה-logon האינטראקטיבי שלכם. בנוסף, משימה שמוגדרת עם "Do not store password" (S4U) רצה בלי network credentials, כך שהכנסת credentials לכספת לא עוזרת כל עוד היא נשארת על S4U. קודם שוקלים תצורה ששומרת את הסיסמה או מעבר לחשבון שירות, ורק אז, אם עדיין נחוץ, מכניסים את ה-credentials לכספת של חשבון ההרצה עצמו.