Certificate Store ב-Windows —‏ CurrentUser או LocalMachine, לאן שמים

· עודכן בתאריך: · · certificates, Windows, אבטחה, PKI, TLS, PowerShell, אפליקציות עסקיות, צוות IT

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

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

Go Komura (2026). Certificate Store ב-Windows —‏ CurrentUser או LocalMachine, לאן שמים. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22175571 https://comcomponent.com/he/blog/windows-certificate-store-guide/

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

“בעדכון המחשב לאימות זכאות מקוון הכנסנו מחדש client certificate למחשב החדש, והחיבור נקטע”, “במכונת הפיתוח מתחברים ל-API של הבנק, וכשהפכנו ל-Windows service מתקבל "ה-certificate לא נמצא"”, “מלכתחילה לא ברור מי האמיתי — ה-certificate שרואים ב-certmgr.msc או זה שרואים ב-certlm.msc” — כשעושים ב-Custom Software Development שילוב Web API עם client certificate, ייעוץ מהסוג הזה מגיע באופן קבוע.

אימות זכאות מקוון במוסדות רפואיים, הגשה אלקטרונית, API בנקאי, EDI מול שותפים. Client certificates, שפעם נגעו בהם רק אנשי תשתית בארגונים גדולים, הם היום עניין לאנשי IT בעסקים קטנים ובינוניים ולמפתחי אפליקציות עסקיות. ותקלות סביב certificates מתכנסות בפועל לכמה דפוסים. שמים במקום הלא נכון, שוכחים הרשאות למפתח הפרטי, שוכחים תוקף — שלושת אלה.

המאמר הזה מיועד למפתחי אפליקציות עסקיות שמשתמשים ב-client certificate, ולאנשי IT שמקבלים על עצמם החלפת certificates. סביב ההחלטה “לשים ב-CurrentUser או ב-LocalMachine” הוא מסדר בבת אחת את מבנה Certificate Store ב-Windows, הענקת הרשאות למפתח הפרטי, inventory של תוקף ב-PowerShell, וקוד שימוש מ-.NET. התוכן מבוסס על מקורות ראשוניים של Microsoft Learn נכון לאוגוסט 2026.

1. קודם כל, המסקנות

  • ל-Certificate Store ב-Windows יש שני קווים: CurrentUser ו-LocalMachine. CurrentUser שונה לכל חשבון (תחת HKEY_CURRENT_USER ב-Registry), ו-LocalMachine משותף לכל המחשב (תחת HKEY_LOCAL_MACHINE).12
  • יש גם שני כלי ניהול. certmgr.msc פותח את CurrentUser, certlm.msc את LocalMachine. מ-PowerShell זה Cert:\CurrentUser ו-Cert:\LocalMachine.34
  • לאן שמים נקבע לפי “כמי רצה התוכנית שמשתמשת ב-certificate”. באפליקציה של משתמש אינטראקטיבי — CurrentUser; בהרצה בלי פיקוח של Windows service, IIS או Task Scheduler — ככלל LocalMachine (טבלת ההחלטה בפרק 3).
  • הסיבה ל-“בפיתוח עבד, ובהפיכה ל-service לא נמצא” כמעט תמיד אחת. Certificate שמפתח שם ב-CurrentUser שלו אינו נראה מ-CurrentUser של service שרץ בחשבון אחר (פרק 3).
  • Certificate ומפתח פרטי הם דבר שונה. עצם השמה ב-LocalMachine אינה אומרת שחשבון ה-service יכול לקרוא את המפתח הפרטי. מעניקים הרשאת קריאה לחשבון ההרצה ב-Manage Private Keys ב-certlm.msc.5
  • בייבוא pfx, המפתח הפרטי כברירת מחדל אינו ניתן לייצוא. Import-PfxCertificate מייבא כך שאי אפשר לייצא מחדש את המפתח הפרטי אלא אם מציינים -Exportable. זו לא תקלה; זו ברירת מחדל רצויה.6
  • פקיעת תוקף מונעים באוטומציית inventory. אפשר לשלוף באופן מכני certificates שיפקעו בתוך מספר ימים שצוין, כמו Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 60.4
  • קיבוע thumbprint בקוד או בתצורה מת, בכל עדכון certificate. ל-certificate חדש תמיד יש thumbprint אחר. הבסיס בתכנון הוא הוצאה לתצורה + תקופת מקביליות של ישן וחדש (פרקים 5 ו-7).

ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 41, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle

2. תמונת Certificate Store — שני מקומות ו-logical stores

2.1. שני הקווים, CurrentUser ו-LocalMachine

Certificate Store ב-Windows נחלק בגדול לשני “מקומות”.1

  • Certificate Store של המחשב (LocalMachine): אחד למחשב, משותף לכל המשתמשים וה-services במחשב. הישות נמצאת תחת HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates ב-Registry.2
  • Certificate Store של המשתמש (CurrentUser): שונה לכל חשבון משתמש. הישות נמצאת תחת HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates, כלומר חלק מפרופיל המשתמש.2

יש גם store לפי service account,3 והישות היא מפתח Registry לפי שם ה-service.2 מה שצריך לתפוס קודם בשטח הם השניים הראשונים.

יש מפרט חשוב אחד. כל logical store ב-CurrentUser, מלבד Personal, מציג בירושה את תוכן ה-store באותו שם ב-LocalMachine.1 למשל אם שמים certificate של CA פנימית ב-Trusted Root Certification Authorities ב-LocalMachine, הוא יופיע גם ב-Trusted Root Certification Authorities של כל המשתמשים. ולהפך, רק Personal אינו מורש, ולכן ל-client certificate (מה ששמים ב-Personal) צריך להחליט בעצמכם “ממי הוא צריך להיראות”. האסימטריה הזו היא גיבורת המאמר כולו.

LocalMachine ו-CurrentUserLocalMachine הוא אחד למחשב ומשותף לכל המשתמשים וה-services, ו-CurrentUser שונה לכל חשבון ומציג בירושה את תוכן המחשב מלבד Personalמשתמש (CurrentUser)שונה לכל חשבוןמחשב (LocalMachine)אחד למחשב, משותף לכל המשתמשים וה-servicesנראה בירושת תוכןירושהירושהPersonal (My)※ אינו מורש = אתם מחליטים לאן לשיםTrusted Root Certification Authorities (Root)Intermediate Certification Authorities (CA)Trusted Publishers (TrustedPublisher)Personal (My)Trusted Root Certification Authorities (Root)Intermediate Certification Authorities (CA)Trusted Publishers (TrustedPublisher)

איור 1: CurrentUser מציג בירושה את תוכן LocalMachine מלבד Personal; את מקום ה-client certificate צריך להחליט בעצמכם.

2.2. ה-logical stores העיקריים

בתוך כל מקום יש logical stores לפי תפקיד. התיקיות שרואים ב-certmgr.msc / certlm.msc הן אלה, ומ-PowerShell ומשורת פקודה משתמשים בשם הפנימי באנגלית.24

שם תצוגה שם פנימי מה שמים שם
Personal My Certificates שהמחשב או המשתמש הזה משתמש בהם. Client certificates ו-server certificates כאן. גם הקישור למפתח הפרטי כאן
Trusted Root Certification Authorities Root Certificates של root CA שהם נקודת האמון. CA שמתחת למה ששמים כאן “מהימנה”
Intermediate Certification Authorities CA Certificates של intermediate CA שמחברים בין השורש לקצה. חומר לבניית שרשרת
Trusted Publishers TrustedPublisher Certificates שסומכים עליהם כמפרסם של תוכנה חתומה (פרק 8)

2.3. שלושה חלונות הצצה — certmgr.msc / certlm.msc / כונן Cert:

יש שלושה אמצעים לראות את אותו store.34

  • certmgr.msc: MMC snap-in שפותח את CurrentUser.
  • certlm.msc: MMC snap-in שפותח את LocalMachine.
  • כונן Cert: ב-PowerShell: אפשר לתפעל את ה-store כמו מערכת קבצים בהיררכיה Cert:\CurrentUser\... ו-Cert:\LocalMachine\.... Certificates מזוהים ב-thumbprint.

כשמוסיפים ידנית snap-in של certificates ל-mmc.exe בוחרים יעד משלושה סוגים: “User account”, “Computer account”, “Service account”. משתמש שאינו Administrator יכול לנהל רק את Store של חשבון המשתמש שלו.3

הצעד הראשון בחקירת תקלה הוא ליישר “איזה store האפליקציה רואה” עם “איזה store אתם רואים”. אם חוקרים תקלת service תוך מבט ב-certmgr.msc, המקום שונה ולעולם לא תגיעו לתשובה.

3. לאן לשים — טבלת החלטה לפי צורת ההרצה של התוכנית

קריטריון אחד. בחשבון של מי רצה התוכנית שמשתמשת ב-certificate.

צורת הרצה חשבון הרצה ה-store לשים הערה
אפליקציה שולחנית שמשתמש אינטראקטיבי מפעיל המשתמש המחובר עצמו CurrentUser (Cert:\CurrentUser\My) נדרשת הטמעה לכל חשבון שמשתמש. במחשב משותף עם כמה אנשים שוקלים גם LocalMachine
Windows service LocalSystem / NETWORK SERVICE / service account ייעודי LocalMachine (Cert:\LocalMachine\My) מלבד LocalSystem (NETWORK SERVICE, חשבון ייעודי וכו’) חובה להעניק הרשאת קריאה למפתח הפרטי (פרק 4). LocalSystem קורא בהרשאת SYSTEM כברירת מחדל
אפליקציית web על IIS זהות ה-application pool LocalMachine כמו למעלה
הרצה בלי פיקוח ב-Task Scheduler (הרצה בין שהמשתמש מחובר ובין שלא) החשבון שצוין במשימה מומלץ LocalMachine אפשר גם ב-CurrentUser של חשבון ההרצה, אבל זה רק מוסיף בדיקות של פרופיל ושל נראות ה-store, בלי יתרון ממשי
הגשה אלקטרונית ואימות web בדפדפן המשתמש המחובר עצמו CurrentUser טבעי גם במובן של “לא לתת לאחרים מלבד מי שחילקתם לו”

כשמסופקים, מה שרץ בלי פיקוח — LocalMachine; מה שאדם מפעיל — CurrentUser.

3.1. ניתוח התקלה הקלאסית — “בפיתוח עבד, ובהפיכה ל-service לא נמצא”

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

  1. המפתח מייבא pfx בלחיצה כפולה במחשב שלו. ברירת המחדל של האשף היא “Current User”, ולכן ה-certificate נכנס ל-CurrentUser של חשבון המפתח.
  2. האפליקציה בפיתוח רצה מ-Visual Studio, כלומר בחשבון המפתח, ולכן פתיחת StoreLocation.CurrentUser מוצאת את ה-certificate. עובד.
  3. בשרת production רושמים כ-Windows service. ה-service רץ כ-NETWORK SERVICE או כחשבון ייעודי.
  4. ה-CurrentUser שהקוד של ה-service פותח הוא CurrentUser של חשבון הרצת ה-service. שם ריק. “ה-certificate לא נמצא”.
בפיתוח עבד, וכ-service לא נמצאCertificate שהוכנס ל-CurrentUser של המפתח אינו נראה מ-CurrentUser של service שרץ בחשבון אחרשרת productionמכונת פיתוחמציבים את אותה תוכניתה-CurrentUser שהקוד פותח הואCurrentUser של חשבון ה-serviceרישום כ-Windows serviceחשבון ההרצה הוא NETWORK SERVICE וכו'שם ריק→ \ה-certificate לא נמצא\נכנס ל-CurrentUserשל חשבון המפתחייבוא בלחיצה כפולה על pfxברירת המחדל באשף היא \Current User\הרצה מ-Visual Studio= רץ בחשבון המפתחפתיחת CurrentUser מוצאת→ עובד

איור 2: CurrentUser של המפתח ו-CurrentUser של חשבון ה-service שונים; הרצה בפיתוח אינה מבטיחה שה-certificate יימצא ב-production.

הנקודה היא של-CurrentUser יש “כמספר החשבונות”. גם אם Administrator פותח certmgr.msc ואומר “הנה, זה בפנים”, זה ה-store של ה-Administrator עצמו, לא של חשבון ה-service. הטיפול אינו העתקה מזדמנת אלא לשים מחדש ב-LocalMachine, וליישר גם את הקוד ל-StoreLocation.LocalMachine. והענקת ההרשאות בפרק הבא באה כחבילה אחת.

4. מפתח פרטי והרשאות גישה — התקלה הקלאסית השנייה

4.1. Certificate ומפתח פרטי הם דבר שונה

מה שנראה ברשימת Certificate Store הוא ה-certificate (מידע ציבורי), לא המפתח הפרטי עצמו. מה שנחוץ בפועל ב-client authentication הוא עיבוד חתימה במפתח הפרטי, ולכן “נראה ברשימה” ו”אפשר להשתמש” הם בעיה נפרדת. אם מבלבלים ביניהם מתקבלת תקלה קשה לראות: “ה-certificate קיים אבל ה-handshake של TLS נכשל”, “שגיאה פנימית בסגנון Access Denied”.

4.2. ייבוא pfx בפועל — ייצוא כן או לא הוא החלטה

זוג ה-certificate והמפתח הפרטי מועבר בקובץ pfx (PKCS #12), ומייבאים ל-store ב-Import-PfxCertificate.6

$pwd = Get-Credential -UserName '(הזינו סיסמה למטה)' -Message 'סיסמת ה-PFX'
Import-PfxCertificate -FilePath C:\certs\client.pfx `
    -CertStoreLocation Cert:\LocalMachine\My -Password $pwd.Password

החשוב כאן הוא התנהגות ברירת המחדל: כל עוד לא מצרפים -Exportable, אי אפשר לייצא מחדש את המפתח הפרטי שיובא.6 לשים הכול כ-exportable “כדי שנוכל להעביר אחר כך” זה להוסיף נתיב אחד להוצאת מפתח פרטי. מפעילים שמירה בטוחה של קובץ ה-pfx המקורי, וב-store המפתח הפרטי אינו ניתן לייצוא כבסיס — זו ההמלצה שלנו. ושמירת קובץ ה-pfx המקורי והסיסמה שלו היא בדיוק מה שנוטה להישאר בטקסט גלוי. את החשיבה מסדרים ב”שמירת סודות באפליקציות Windows — להימנע מתצורה גלויה עם DPAPI” וב”טיפול בטוח ב-Credentials ב-PowerShell”.

4.3. הענקת הרשאות מפתח פרטי ל-service account

למפתח הפרטי של certificate ב-LocalMachine, בדרך כלל כברירת מחדל אי אפשר לקרוא מלבד Administrators ו-SYSTEM. לכן service שרץ כ-LocalSystem קורא את המפתח הפרטי כברירת מחדל, אבל כשמריצים בחשבון אחר — NETWORK SERVICE, service account ייעודי, זהות application pool של IIS — מעניקים במפורש הרשאת קריאה לחשבון ההרצה. את ההליך אפשר לעשות מממשק ה-snap-in של certificates.5

  1. פותחים certlm.msc (או snap-in certificates ליעד Computer account).
  2. ב-Personal → Certificates לוחצים ימני על ה-certificate היעד, ומתוך All Tasks פותחים Manage Private Keys.
  3. בלשונית Security מוסיפים את חשבון ההרצה (NETWORK SERVICE, service account ייעודי, זהות application pool של IIS וכו’) ומתירים Read.5

אין צורך ב-Full Control. לחתימה מספיקה קריאה. ולהפך, לתת Everyone Full Control כי “זה לא עובד” זה להוריד את המפתח הפרטי לטיפול כמו סיסמה גלויה — אסור בהחלט. הצבה ב-LocalMachine והענקת הרשאות למפתח הפרטי תמיד חבילה אחת — לכתוב את זה בספר ההליך מספיק כדי שהתקלות מהסוג הזה ייעלמו.

5. למנוע תקלת פקיעת תוקף — inventory, החלפה, ledger

5.1. Inventory ב-PowerShell

תוקף ה-certificate נמצא במאפיין NotAfter. אפשר לעשות inventory באופן מכני עם Get-ChildItem על כונן Cert:.4

# רשימת Personal ב-LocalMachine לפי תוקף
Get-ChildItem Cert:\LocalMachine\My |
    Sort-Object NotAfter |
    Format-Table Thumbprint, Subject, NotAfter

# שליפה רק של מה שיפקע בתוך 60 ימים (0 מחזיר שכבר פג)
Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 60

-ExpiringInDays הוא פרמטר שמחזיר “certificates שיפקעו בתוך מספר הימים שצוין”, ו-0 מחזיר certificates שכבר פג תוקפם.4 הופכים את זה למשימה מתוזמנת חודשית על כל השרתים, ומרכזים תוצאות לדואר או ל-inventory — וזה לבדו כמעט מונע תקלות בסגנון “בבוקר יום שני אימות הזכאות לא עובר כי פג התוקף”.

5.2. הליך ההחלפה — תקופת מקביליות ומלכודת ה-thumbprint

עדכון certificate אינו “מוחקים ושמים” אלא “מוסיפים, מחליפים, מאשרים, ואז מוחקים”.

  1. מייבאים את ה-certificate החדש (pfx) לאותו store. ה-thumbprint שונה, ולכן ישן וחדש יכולים לדור יחד באותו store.
  2. מעניקים הרשאות למפתח הפרטי של ה-certificate החדש (פרק 4). כאן קל לשכוח בעדכון. ההרשאה צמודה לכל מפתח פרטי של certificate, ולכן אחרי החלפת certificate מעניקים מחדש.
  3. דיווח למערכת היעד (כש-API דורש רישום מראש של ה-certificate) משלימים קודם, תוך המשך תפעול ב-certificate הישן, ומבטיחים תקופת מקביליות שבה גם ישן וגם חדש מתקבלים. אם מחליפים קודם, הצד השני דוחה את ה-certificate החדש והתקשורת ב-production נעצרת.
  4. מחליפים את תצורת האפליקציה ל-certificate החדש, ומאשרים פעולה.
  5. אחרי תקופה מספקת, מוחקים את ה-certificate הישן.
עדכון certificate מוסיפים ואז מחליפיםמייבאים pfx חדש לאותו store, מעניקים הרשאות, רושמים מראש אצל היעד, מחליפים thumbprint, ואחרי תקופת המקביליות מוחקים את הישן1. ייבוא pfx חדש לאותו store(ישן וחדש יחד)2. הענקת הרשאותלמפתח הפרטי של ה-certificate החדש3. רישום מראש אצל היעד(המשך תפעול ב-certificate הישן)4. החלפת thumbprint בתצורההחלפה ואישור פעולה5. אחרי תקופת המקביליותמחיקת ה-certificate הישן

איור 3: סדר החלפת certificate הוא הוספה → הרשאות → רישום מראש → החלפת תצורה → מחיקת הישן; לא לשכוח עדכון thumbprint.

המלכודת הגדולה כאן היא thumbprint שכתובה בקובץ תצורה או בקוד. Thumbprint ייחודי לכל certificate, ולכן בעדכון היא תמיד משתנה. אם ולו מקום אחד עדיין מפנה ל-thumbprint הישנה, מתקבל “עדכנו את ה-certificate ועדיין אי אפשר להתחבר”. הדרך הבטוחה היא לנהל ב-inventory איפה כתובה ה-thumbprint (תצורת אפליקציה, קישור IIS, סקריפט, דיווח ליעד).

5.3. ההמלצה ל-inventory של certificates

Inventory — די בגליון Excel אחד בהתחלה. לכל הפחות עמודות שימוש / מנפיק / Subject / thumbprint / מקום (שם שרת + store) / חשבון עם הרשאת מפתח פרטי / תוקף / קישור להליך עדכון / אחראי, ומצליבים מול תוצאת ה-inventory ב-5.1. מהות תקלת ה-certificates אינה בעיית טכנולוגיה אלא בעיית “לאף אחד אין רשימה”, ולכן ה-inventory הוא מה שהכי עובד.

6. קריאת אימות וכישלון — שרשרת והפצת שורש

6.1. יסודות אימות השרשרת ו-certutil

שגיאות בסגנון “ה-certificate הזה אינו מהימן” הן מצב שבו השרשרת (נתיב ההוכחה) מה-leaf certificate עד root CA קרועה איפשהו. ל-isolation נוח certutil.7

שלוש הסיבות הקלאסיות לחיתוך אימות שרשרתאי אפשר להשיג intermediate CA, השורש לא הופץ, או שפג תוקף ה-leaf, וכל אחד מהם גורם לשגיאת אמוןאי אפשר להשיג(לא בהצגה, לא ב-AIA, לא ב-store)לא הופץפג תוקףה-leaf certificate(client certificate / server certificate)certificate של intermediate CAמקום: Intermediate Certification Authorities (CA)certificate של root CAמקום: Trusted Root Certification Authorities (Root)אי אפשר לבנות שרשרת(סיבה קלאסית 1)שגיאת אינו מהימן(סיבה קלאסית 2)שגיאת תקופת תוקף(סיבה קלאסית 3)

איור 4: השרשרת נחתכת כשחסר intermediate CA או root, או בגלל תקופת תוקף; קובעים את השכבה ב-certutil.

:: בניית שרשרת ואימות לקובץ certificate (כולל הבאת URL לבדיקת revocation)
certutil -urlfetch -verify client.cer

:: אם האפליקציה היעד משתמשת ב-CurrentUser, מאמתים באותו הקשר עם -user
certutil -user -urlfetch -verify client.cer

:: dump לתוכן ה-store (-user פונה ל-CurrentUser)
certutil -store My
certutil -user -store My

certutil -verify מאמת certificate, CRL ושרשרת, ואם לא מציינים CACertFile הוא בונה שרשרת מלאה ומאמת.7 הפלט ארוך, אבל אפשר לקרוא באיזו שכבה נקטע האמון והאם מידע ה-revocation הגיע. הסיבות הטיפוסיות הן (1) אי אפשר להשיג certificate של intermediate CA (העמית ב-TLS לא שלח, גם ממידע AIA ב-certificate אי אפשר לקבל, וגם לא נמצא ב-store Intermediate Certification Authorities), (2) השורש של ה-CA הפנימית לא הופץ ל-Trusted Root Certification Authorities, (3) פג תוקף ה-certificate עצמו. Intermediate CA נפתר גם בהצגה מהעמית או בהבאה אוטומטית דרך AIA, ולכן הצבה ב-store כדאי לראות כ-“אחד האמצעים להבטיח”.

6.2. הפצת שורש של CA פנימית ו-self-signed — ב-GPO/Intune

כשמשתמשים ב-CA פנימית או ב-certificate self-signed לבדיקה, צריך להפיץ את ה-root certificate לכל מחשב. לא שמים ידנית מחשב-מחשב, אלא מעמיסים על מנגנון הפצה.

  • סביבת Active Directory (GPO): מייבאים certificate ל-Trusted Root Certification Authorities תחת Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policies ב-Group Policy, והוא מופץ למחשבי היעד.8
  • סביבה בניהול Intune: מפיצים certificates של root/intermediate CA בפרופיל Trusted certificate. ב-Windows אפשר לבחור את Store היעד (root/intermediate של המחשב, intermediate של המשתמש).9

כפי שנאמר ב-2.1, אם שמים ב-Root של LocalMachine, כל המשתמשים סומכים.1 ולכן צריך להביט גם בסיכון ההפוך. תפעול שמכניס certificate self-signed ל-Trusted Root Certification Authorities הוא נטיעת נקודת אמון חדשה במחשב. אם המפתח הפרטי דולף, זה בסיס להנפקת certificates שמתחזים לכל אתר או תוכנה. לתפעול קבוע הנתיב הוא להקים CA פנימית עם הגנה נאותה על המפתח, או להתקרב ל-certificate של CA ציבורית; root self-signed ככלל הוא “סביבת בדיקה בלבד, עם תוקף חתוך”.

7. מבט המפתח — שימוש נכון ב-store מ-.NET

7.1. חיפוש לפי thumbprint ב-X509Store

מ-.NET פותחים store ב-X509Store ומשיגים certificate ב-Find.1011

using System.Security.Cryptography.X509Certificates;

static X509Certificate2 GetClientCertificate(string thumbprint)
{
    using var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    var found = store.Certificates.Find(
        X509FindType.FindByThumbprint, thumbprint, validOnly: true);

    if (found.Count == 0)
        throw new InvalidOperationException(
            $"ה-certificate לא נמצא: thumbprint={thumbprint}, " +
            $"מקום={store.Location}\\{store.Name}");

    var cert = found[0];
    if (!cert.HasPrivateKey)
        throw new InvalidOperationException(
            $"ה-certificate קיים אבל אין מפתח פרטי מקושר (ייבוא מ-.cer " +
            $"וכו'): thumbprint={thumbprint}, מקום={store.Location}\\{store.Name}");

    return cert;
}

ההחלטה מפרק 3 מתחברת לכאן ישירות. בקוד שרץ כ-service — StoreLocation.LocalMachine; באפליקציה אינטראקטיבית — StoreLocation.CurrentUser. עוד נקודה: שימו לב לארגומנט השלישי validOnly של Find. true מחזיר רק certificates תקפים שעברו אימות.11 זה ביטוח לא לתפוס certificate שפג תוקפו, אבל גם certificate self-signed לבדיקה שהשרשרת שלו אינה מהימנה נופל לצד “לא נמצא”, ולכן כש”הוא בפנים אבל לא נמצא” חושדים גם כאן. ובהודעת השגיאה כשלא נמצא תמיד שמים, כמו בדוגמה למעלה, איזה store חיפשתם. זמן החקירה של תקלת פרק 3 משתנה בסדרי גודל.

7.2. לשים client certificate על HttpClient

את ה-certificate שהושג מוסיפים ל-HttpClientHandler.ClientCertificates ומציגים לשרת. האוסף הזה הוא קבוצת ה-certificates שמוצגת לשרת ב-certificate-based client authentication.12

var handler = new HttpClientHandler();
handler.ClientCertificates.Add(GetClientCertificate(thumbprint));

var client = new HttpClient(handler);
// מכאן משתמשים כ-HttpClient רגיל

ב-.NET Core מצוין בתיעוד שאם ל-certificate יש מאפיין Key Usage, הוא לא ישמש לשליחת בקשה אלא אם הוא כולל Digital Signature.12 כשאתם בצד שמבקש הנפקת client certificate, העבירו נכון את השימוש (Client Authentication). ו-HttpClient עם דפוס יצירה שגוי גורם לדלדול sockets ולבעיות מעקב DNS. תכנון שמאריך את חיי ה-handler כולו מטופל ב”אסור לעטוף HttpClient ב-using”.

7.3. בעיית thumbprint מקובעת שמתה בהחלפה

חיפוש לפי thumbprint בטוח, אבל אם משובצת thumbprint בקוד כל עדכון certificate דורש build ושחרור. הטיפול בתכנון הוא בשלושה שלבים.

  • מינימום: מוציאים את ה-thumbprint לקובץ תצורה (appsettings וכו’) כדי שאפשר יהיה להחליף בלי שחרור. את מקום התצורה שמים ב-inventory של 5.3.
  • צעד נוסף: מחפשים לפי Subject או מנפיק, ומשלבים עם validOnly: true כדי לבחור “מבין התקפים כעת בשם הזה, זה עם NotAfter הרחוק ביותר”. בתקופת מקביליות הוא עובר אוטומטית ל-certificate החדש. אבל יש סיכון לתפוס certificate לא מכוון באותו שם, ולכן מאשרים מנפיק ומוציאים ללוג כחבילה. והמעבר האוטומטי הזה מתקיים רק כשהיעד אינו דורש רישום מראש של ה-certificate. ב-API שדורש רישום מראש (5.2) הוא עלול לעבור לבד ל-certificate שיובא בלבד ועדיין לא נרשם, ולעצור תקשורת — לכן נשארים בשיטת ההוצאה לתצורה, ומחליפים אחרי שאישרתם שהרישום הושלם.
  • סוגרים בתפעול: בכל שיטה, בהפעלה משאירים בלוג “איזה certificate (thumbprint, תוקף) נבחר”. השורה הזו עובדת גם בחקירת תקלה וגם בהצלבה מול ה-inventory.

8. הקשר ל-code signing certificate —‏ store Trusted Publishers

עד כאן טופלו certificates לתקשורת (TLS), אבל ב-Certificate Store מתגורר עוד עולם — code signing. נקודת המגע היא store Trusted Publishers (TrustedPublisher) בטבלה ב-2.2, המקום שבו רושמים כמהימן את certificate המפרסם של תוכנה חתומה. הוא קיים גם במקום המשתמש וגם במקום המחשב,10 ומשמש בתפעול כמו להפיץ ב-GPO את מפרסם האפליקציה הפנימית ל-TrustedPublisher בכל מחשב.

אם אתם בצד “שמפיץ” אפליקציה וצריכים לטפל ב-code signing ובאזהרת SmartScreen (“Windows protected your PC”), זה מרוכז במאמר נפרד “למה מופיע "Windows protected your PC"”. הידע במאמר הזה (שני קווי ה-store, הפצת שורש) משמש כמו שהוא כידע רקע.

9. סיכום

  • ל-Certificate Store שני קווים: CurrentUser ו-LocalMachine. certmgr.msc / certlm.msc / כונן Cert: הם שלושה חלונות לאותו דבר. הצעד הראשון בחקירה הוא ליישר “על איזה store מדברים”.
  • את מקום ההשמה קובעים לפי “כמי התוכנית רצה”. הרצה בלי פיקוח (service, IIS, task) —‏ LocalMachine; אפליקציה אינטראקטיבית — CurrentUser, ככלל.
  • “בפיתוח עבד, ובייצור לא נמצא” נגרם מכך ש-CurrentUser של המפתח ו-CurrentUser של חשבון ה-service הם דבר שונה. מיישרים ל-LocalMachine + StoreLocation.LocalMachine.
  • הצבה ב-LocalMachine והענקת הרשאת קריאה ב-Manage Private Keys הן חבילה אחת. לא לשכוח להעניק מחדש בעדכון.
  • ייבוא pfx כברירת מחדל אינו ניתן לייצוא. -Exportable רק כשבאמת נחוץ. כוללים בתכנון גם שמירת קובץ ה-pfx המקורי והסיסמה.
  • פקיעת תוקף מונעים ב-inventory מחזורי עם Get-ChildItem Cert: ... -ExpiringInDays וב-inventory של certificates. החלפה בסדר “הוספה → החלפה → אישור → מחיקה”, עם זהירות לדליפת עדכון thumbprint בתצורה.
  • Isolation של שרשרת ב-certutil -urlfetch -verify. שורש של CA פנימית מפיצים ב-GPO/Intune, ותפעול שמכניס self-signed לשורש — סביבת בדיקה בלבד, עם תוקף.
  • בקוד מוציאים thumbprint לתצורה ומשאירים בלוג את ה-certificate שנבחר. זה לבדו משנה את הטיפול בתקלות שמקורן ב-certificate.

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

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

KomuraSoft LLC מטפלת בפיתוח אפליקציות עסקיות שמשלבות Web API עם client certificate (API בנקאי, אימות זכאות מקוון וכו’), בחקירת תקלות בסגנון “ה-certificate לא נמצא” ו”אחרי עדכון אי אפשר להתחבר”, ובארגון הליך החלפת certificates. אפשר להתייעץ כבר מהשלב שבו לא ברור איזה store להסתכל עליו.

מקורות

  1. Microsoft Learn, Local Machine and Current User Certificate Stores. על כך ש-Certificate Store של המחשב מקומי למחשב ומשותף לכל המשתמשים ונמצא תחת HKEY_LOCAL_MACHINE; על כך ש-Certificate Store של המשתמש הוא לפי חשבון משתמש ונמצא תחת HKEY_CURRENT_USER; ועל כך ש-CurrentUser יורש את תוכן LocalMachine מלבד Personal (certificate שנוסף ל-Trusted Root Certification Authorities של המחשב מופיע גם באותו store אצל כל משתמש). ↩ ↩2 ↩3 ↩4

  2. Microsoft Learn, System Store Locations. על מיקום ה-Registry של CERT_SYSTEM_STORE_CURRENT_USER / CERT_SYSTEM_STORE_LOCAL_MACHINE (Software\Microsoft\SystemCertificates תחת HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE בהתאמה); על כך שה-logical stores המוגדרים הם MY, Root, Trust, CA; על כך ש-store לשירות נמצא במפתח Registry לפי שם ה-service (Software\Microsoft\Cryptography\Services\ServiceName\SystemCertificates); ועל כך שקיים בנפרד store להפצה ב-Group Policy. ↩ ↩2 ↩3 ↩4 ↩5

  3. Microsoft Learn, How to: View certificates with the MMC snap-in. על כך ש-certlm.msc מנהל certificates של המכשיר המקומי (LocalMachine) ו-certmgr.msc מנהל certificates של CurrentUser; על כך של-snap-in של certificates יש שלושה יעדים: Computer account, User account, Service account; ועל כך שמשתמש שאינו Administrator יכול לנהל רק certificates של חשבון המשתמש שלו. ↩ ↩2 ↩3 ↩4

  4. Microsoft Learn, about_Certificate_Provider. על כך שכונן Cert: ב-PowerShell הוא מרחב שמות היררכי עם שני מקומות store, CurrentUser ו-LocalMachine; על כך שאפשר למנות stores ו-certificates ב-Get-ChildItem; על כך שהפרמטר -ExpiringInDays מחזיר certificates שיפקעו בתוך מספר הימים שצוין (0 לשכבר פג); על פרמטרים דינמיים כמו -CodeSigningCert; על כך שתוקף נשמר במאפיין NotAfter; ועל כך ש-certificates מזוהים ב-thumbprint. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  5. Microsoft Learn, How to Modify Private Key Permissions to Support Management Server or Streaming Server. על ההליך שבו ב-snap-in certificates ליעד LocalMachine פותחים Manage Private Keys, ובלשונית Security מוסיפים הרשאת Read לחשבון הרצת ה-service (למשל Network Service). ↩ ↩2 ↩3

  6. Microsoft Learn, Import-PfxCertificate. על כך ש-Import-PfxCertificate מייבא certificate ומפתח פרטי מקובץ PFX ל-store שצוין; על כך שאם לא מציינים את המתג -Exportable אי אפשר לייצא את המפתח הפרטי שיובא; ועל התחביר ודוגמאות השימוש בפרמטרים -CertStoreLocation, -Password, -FilePath. ↩ ↩2 ↩3

  7. Microsoft Learn, certutil. על כך ש-certutil -verify מאמת certificate, CRL ושרשרת certificates, ושבלי ציון קובץ certificate של CA הוא בונה שרשרת מלאה ומאמת; על זמינות האפשרות -urlfetch; ועל כך ש-certutil -store עושה dump ל-Certificate Store, ושעם האפשרות -user ניגשים ל-CurrentUser במקום ל-LocalMachine. ↩ ↩2

  8. Microsoft Learn, Distribute Certificates to Client Computers by Using Group Policy. על ההליך לייבא certificate ל-Trusted Root Certification Authorities תחת Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policies ב-Group Policy ולהפיץ למחשבי לקוח ב-domain, ועל ההרשאות הנדרשות (ברמה של Domain Admins / Enterprise Admins). ↩

  9. Microsoft Learn, Create trusted certificate profiles in Microsoft Intune. על כך שפרופיל Trusted certificate ב-Intune הוא מנגנון להפצת certificate של root או intermediate CA למכשירים מנוהלים; על כך שהוא משמש כהנחה לפרופילי certificate SCEP/PKCS כדי לבסס אמון ב-root CA; ועל כך שב-Windows אפשר לבחור כ-store יעד Computer certificate store - Root, Computer certificate store - Intermediate, User certificate store - Intermediate. ↩

  10. Microsoft Learn, X509Store Class. על כך שאפשר לבנות X509Store עם StoreName ו-StoreLocation (CurrentUser / LocalMachine), לפתוח store בשיטת Open וב-OpenFlags (ReadOnly, OpenExistingOnly וכו’), ולהשיג אוסף certificates במאפיין Certificates; על כך ששמות ה-store הסטנדרטיים כוללים My, Root, CA, TrustedPublisher וכו’; ועל כך ש-TrustedPublisher קיים גם ב-CurrentUser וגם ב-LocalMachine. ↩ ↩2

  11. Microsoft Learn, X509Certificate2Collection.Find(X509FindType, Object, Boolean) Method. על כך ששיטת Find מחפשת certificates לפי X509FindType (FindByThumbprint וכו’) וערך חיפוש; ועל כך שכשמציינים true בארגומנט השלישי validOnly מוחזרים רק certificates תקפים שעברו אימות. ↩ ↩2

  12. Microsoft Learn, HttpClientHandler.ClientCertificates Property. על כך שמאפיין ClientCertificates הוא X509CertificateCollection שמוצג לשרת ב-certificate-based client authentication; ועל כך שב-.NET Core, אם ל-certificate יש מאפיין Key Usage, נדרש שיכלול Digital Signature. ↩ ↩2

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

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

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

שאלות נפוצות

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

מה ההבדל בין certmgr.msc ל-certlm.msc?
ה-Certificate Store שהם פותחים שונה. certmgr.msc פותח את Certificate Store של המשתמש המחובר (CurrentUser), ו-certlm.msc פותח את Certificate Store של המחשב (LocalMachine). Store של המחשב משותף לכל המשתמשים וה-services במחשב, ולניהול נדרשות הרשאות Administrator. משתמש שאינו Administrator יכול לנהל רק את Store של המשתמש שלו. בשניהם התוכן מחולק ל-logical stores כמו Personal ו-Trusted Root Certification Authorities, ומ-PowerShell רואים את אותו מבנה כ-Cert:\CurrentUser ו-Cert:\LocalMachine.
Client certificate — לשים ב-CurrentUser או ב-LocalMachine?
מחליטים לפי "כמי" רצה התוכנית שמשתמשת ב-certificate. באפליקציה שולחנית שמשתמש אינטראקטיבי מפעיל, הבסיס הוא CurrentUser של אותו אדם (Cert:\CurrentUser\My). בתוכנית שרצה בלי פיקוח כ-Windows service, IIS application pool או Task Scheduler, שמים ב-LocalMachine (Cert:\LocalMachine\My) ומעניקים לחשבון ההרצה הרשאת קריאה למפתח הפרטי. CurrentUser שונה לכל חשבון, ולכן certificate שמפתח שם ב-CurrentUser שלו אינו נראה ל-service שרץ בחשבון אחר. זו הסיבה הקלאסית ל"בפיתוח עבד, ובייצור לא נמצא".
כש-Windows service לא מוצא את ה-certificate או לא יכול להשתמש בו, מה בודקים?
שני שלבים. ראשית "איזה store הוא רואה". אם הקוד פותח StoreLocation.CurrentUser, זה CurrentUser של חשבון הרצת ה-service, וזה דבר אחר מה-store שה-Administrator רואה ב-certmgr.msc. מעבירים את ה-certificate ל-LocalMachine, ומתאימים גם את הקוד ל-StoreLocation.LocalMachine. שנית "האם אפשר לקרוא את המפתח הפרטי". לראות את ה-certificate ברשימה ולהשתמש במפתח הפרטי הם דבר שונה, ולמפתח הפרטי ב-LocalMachine בדרך כלל יש גישה כברירת מחדל רק ל-Administrators ול-SYSTEM. ב-certlm.msc פותחים Manage Private Keys מה-certificate היעד, ומעניקים Read לחשבון הרצת ה-service (NETWORK SERVICE וכו').
איך מוצאים מראש פקיעת תוקף של certificate ב-PowerShell?
אפשר לעשות inventory עם Get-ChildItem על כונן Cert:. למשל Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter | Format-Table Thumbprint, Subject, NotAfter מציג את Personal של LocalMachine לפי תוקף. עם הפרמטר -ExpiringInDays אפשר לשלוף רק "certificates שיפקעו בתוך מספר הימים שצוין", ו-0 מחזיר certificates שכבר פג תוקפם. מריצים את זה מדי חודש על כל השרתים ומצליבים מול inventory של certificates — ורוב תקלות "בבוקר אי אפשר להתחבר כי פג התוקף" נמנעות.

פרופיל הכותב

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

Go Komura

מנהל KomuraSoft LLC

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

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

חזרה לבלוג