דילוג לתוכן
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

מפתחות SSH: איך הם עובדים ואיך משתמשים בהם בבטחה

איך מפתחות מארח ומשתמש של SSH עובדים, למה Ed25519 עם passphrase הוא ברירת המחדל, ואיך מגדירים ומקשיחים התחברות במפתח על VM של מעבדה בבעלותך.

מתחילים9 דקות קריאהמאת NotHoly

על מה SSH מגן

SSH ‏(Secure Shell) הוא הפרוטוקול שבו רוב האנשים מתחברים לשרתי Linux, למכונות וירטואליות של מעבדה ולמארחי Git. הוא פותח shell בערוץ מוצפן, ואותו ערוץ יכול להעתיק קבצים או להעביר פורטים. יש לו שלושה תפקידים. הוא מצפין את התעבורה כך שאיש בנתיב הרשת לא יכול לקרוא אותה. הוא מוכיח לשרת מי מתחבר. הוא מוכיח ללקוח מי השרת.

מפתחות עושים את התפקיד השני בלי לשלוח סיסמה ברשת. אפשר לנחש סיסמה או לגנוב אותה בפישינג. זוג מפתחות עובד אחרת. השרת שומר רק את החצי הציבורי. כדי להתחבר, הלקוח שלך חותם על אתגר עם החצי הפרטי, והשרת בודק את החתימה. המפתח הפרטי אף פעם לא יוצא מהמחשב שלך.

יש מקרים ש-SSH לא מגן בהם, והם חשובים כמו הפרוטוקול עצמו. אם המחשב שלך נפרץ, נוזקה שרצה תחת המשתמש שלך יכולה לקרוא את קובץ המפתח הפרטי או לבקש מה-agent שלך לחתום על דברים. אם המפתח הפרטי נגנב וה-passphrase שלו חלש, תוקף יכול לנסות לנחש אותו offline. אם מקבלים את זהות השרת בלי לבדוק אותה, ייתכן שהצד השני הוא בכלל לא השרת.

שני סוגי מפתחות

SSH משתמש בשני סוגי מפתחות שונים, ואנשים מבלבלים ביניהם לעיתים קרובות.

מפתחות מארח מזהים את השרת. לכל שרת SSH יש אחד או יותר, בדרך כלל בנתיב /etc/ssh/ssh_host_*_key. החלק הפרטי נשאר על השרת. החלק הציבורי מוצג לכל לקוח שמתחבר. בפעם הראשונה שהלקוח רואה אותו, הוא שומר אותו בקובץ known_hosts. בחיבורים הבאים, מפתח מארח ששונה מפעיל אזהרה.

מפתחות משתמש מזהים אותך. את הזוג יוצרים על המחשב שלך. המפתח הפרטי נשאר אצלך. המפתח הציבורי עובר לשרת, לקובץ ~/.ssh/authorized_keys של החשבון שרוצים להשתמש בו.

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

למה Ed25519 עם passphrase

OpenSSH תומך בכמה סוגי מפתחות. RSA עדיין עובד, אבל מפתחות RSA חדשים צריכים להיות לפחות 3072 ביט, ושורות המפתח הציבורי ארוכות. מפתחות Ed25519 קצרים, מהירים לאימות ומתוקננים ל-SSH ב-RFC 8709. OpenSSH 9.5 ואילך הופך את Ed25519 לברירת המחדל של ssh-keygen. Ed25519 הוא ברירת המחדל הנכונה למפתח מעבדה, אלא אם מערכת שצריך להגיע אליה מקבלת רק סוג ישן יותר.

passphrase מצפין את קובץ המפתח הפרטי בדיסק. בלעדיו, כל מי שמעתיק את הקובץ יכול להשתמש במפתח. איתו, צריך גם את הקובץ וגם את ה-passphrase. זה מגן מפני התקלות הנפוצות ביותר: גיבוי שנשלח למקום הלא נכון, מפתח שנשאר בתיקייה משותפת, קובץ שסונכרן בטעות לכונן ענן. passphrase לא עוזר אחרי שהמפתח נטען ל-agent ונוזקה רצה בשמך. כדאי לבחור passphrase ארוך, לשמור אותו במנהל סיסמאות ולהחזיק גיבוי של קובץ המפתח במקום בטוח.

איך חיבור עובד

RFC 4253 מתאר את שכבת התעבורה. במבט על, חיבור עובר את השלבים האלה:

  1. הלקוח שלך פותח חיבור TCP לשרת, בדרך כלל בפורט 22.
  2. שני הצדדים שולחים את האלגוריתמים שהם תומכים בהם ומסכימים על החלפת מפתחות. ההחלפה מפיקה סודות משותפים, ומאותה נקודה כל התעבורה מוצפנת.
  3. השרת שולח את מפתח המארח שלו וחתימה על ההחלפה. הלקוח שלך בודק את מפתח המארח מול known_hosts. אם המארח חדש, הלקוח מציג את טביעת האצבע ומבקש אישור.
  4. מתבצע אימות. הלקוח מציע מפתח ציבורי. אם השרת מוצא אותו בקובץ authorized_keys, הוא שולח אתגר. הלקוח שלך חותם על האתגר עם המפתח הפרטי, והשרת בודק את החתימה.

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

טביעות אצבע

טביעת אצבע היא hash קצר של מפתח ציבורי. OpenSSH מציג כברירת מחדל טביעות אצבע של SHA256. שני אנשים יכולים להשוות טביעת אצבע כדי לוודא שהם מחזיקים באותו מפתח ציבורי, בלי להקריא את המפתח כולו.

הפקודות בהמשך הורצו על מחשב Windows 11 עם OpenSSH 9.9p2 ‏(ssh -V), ב-Git Bash. המפתח היה עותק לניסיון שנוצר לצורך הבדיקה הזאת, עם passphrase ריק, כדי שאפשר יהיה להציג כאן את הפלט. למפתח האמיתי שלך תהיה טביעת אצבע אחרת.

bash
ssh-keygen -t ed25519 -C 'lab-key' -f ./lab_ed25519 -N ''
ssh-keygen -lf ./lab_ed25519.pub

הפלט שהתקבל:

text
256 SHA256:2BAyZTrHADdiG1FNwfCwb/fC5vSVZPwfGnZjRaaExc4 lab-key (ED25519)

ssh-keygen -lvf מדפיס את אותה טביעת אצבע עם תמונת random-art. קל יותר להבחין בשינוי בתמונה, אבל משווים את טקסט טביעת האצבע.

מעבדה מעשית

צריך מכונה וירטואלית או מופע ענן בבעלותך ובשליטתך, עם שרת OpenSSH פעיל וחשבון שיכול להשתמש בפקודה sudo. VM מקומי ב-VirtualBox או ב-Hyper-V מתאים. כך גם מופע ענן קטן שמשלמים עליו ואפשר למחוק אותו. לא מריצים את השלבים האלה מול מחשב ששייך למישהו אחר.

שלב 1: יצירת המפתח

bash
ssh-keygen -t ed25519 -C 'lab-key' -f ~/.ssh/lab_ed25519

כשמתבקשים, מזינים passphrase ארוך. הפקודה יוצרת שני קבצים: lab_ed25519 (פרטי) וגם lab_ed25519.pub (ציבורי). רק הקובץ עם הסיומת .pub מיועד לצאת מהמחשב שלך.

שלב 2: בדיקת טביעת האצבע

bash
ssh-keygen -lf ~/.ssh/lab_ed25519.pub

כדאי לרשום את טביעת האצבע, או לפחות את התווים הראשונים. בהמשך משווים אליה שוב.

שלב 3: נעילת קובץ המפתח הפרטי

bash
chmod 600 ~/.ssh/lab_ed25519

ב-Linux וב-macOS, ‏ssh מסרב למפתח פרטי שמשתמשים אחרים יכולים לקרוא. ב-Windows, ‏OpenSSH בודק ACLs של קבצים ולא את ביטי ההרשאות של Unix. במחשב ה-Windows הזה chmod 600 רץ בלי שגיאה, אבל ls -l עדיין הציג -rw-r--r-- אחרי זה. אי אפשר להניח שם שביטי ההרשאות השתנו. אם ssh מתלונן על הרשאות ב-Windows, בודקים את הקובץ עם icacls ומסירים גישה מחשבונות אחרים.

שלב 4: התקנת המפתח הציבורי על ה-VM

bash
ssh-copy-id -i ~/.ssh/lab_ed25519.pub youruser@your-lab-vm

זו הפעם היחידה שמקלידים את סיסמת החשבון בכוונה. הפקודה מוסיפה את המפתח הציבורי אל ~/.ssh/authorized_keys על ה-VM.

החיבור הראשון ל-VM מציג גם טביעת אצבע של מפתח המארח. משווים אותה לטביעה האמיתית. על ה-VM מריצים:

bash
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

אם שתי טביעות האצבע תואמות, מקלידים yes. אם לא, עוצרים. מבררים למה לפני שממשיכים. חוסר התאמה יכול להעיד על כך שה-VM הותקן מחדש, או שמישהו יושב בינך לבין ה-VM.

השלב הזה לא הורץ כאן, כי לא היה VM זמין במחשב הזה. מסיבה זו הפקודות בשלבים 4 עד 6 מוצגות בלי פלט. אפשר לבדוק כל אחת מהן על ה-VM שלך.

שלב 5: התחברות עם המפתח

bash
ssh -i ~/.ssh/lab_ed25519 youruser@your-lab-vm

הלקוח מבקש את ה-passphrase של המפתח ולא את סיסמת החשבון. אם מתקבל shell, המפתח עובד. משאירים את הסשן הזה פתוח לשלב הבא.

שלב 6: כיבוי התחברות בסיסמה

על ה-VM:

bash
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl restart ssh

השורה עם sed מחליפה את שורת PasswordAuthentication, בין אם היא בהערה ובין אם לא. sshd -t בודק את תחביר הקונפיגורציה ועוצר את השרשרת אם הוא נכשל. systemctl restart ssh מחיל את השינוי. ב-Fedora ובמערכות אחרות ממשפחת RHEL השירות נקרא sshd, ולכן משתמשים בשם הזה.

שלושה דברים משתבשים כאן לעיתים קרובות:

  • השורה נדרסת. במערכות Debian ו-Ubuntu רבות, /etc/ssh/sshd_config כולל קבצים מהתיקייה /etc/ssh/sshd_config.d/, והערך הראשון שנקרא עבור מילת מפתח הוא הקובע. בודקים את הערך ש-sshd משתמש בו בפועל:
bash
sudo sshd -T | grep -i '^passwordauthentication'

אחרי השינוי הפלט אמור להיות passwordauthentication no. אם עדיין מופיע yes, מאתרים את הקובץ שקובע את זה ומתקנים שם.

  • השורה חסרה. sed עורך רק שורה קיימת. אם אין שורת PasswordAuthentication, חלה ברירת המחדל, ודף ה-man של sshd_config(5) אומר שברירת המחדל היא yes. מוסיפים את השורה ידנית:
bash
echo 'PasswordAuthentication no' | sudo tee -a /etc/ssh/sshd_config
  • נעילה של עצמך בחוץ. לפני סגירת הסשן משלב 5, פותחים טרמינל שני ומתחברים עם המפתח. סוגרים את הטרמינל הראשון רק אחרי שהשני עובד. אם הגישה אבדה, משתמשים בקונסולת ה-VM מה-hypervisor או מלוח הבקרה של הענן כדי לתקן את הקונפיגורציה.

אחר כך בודקים מהמחשב שלך שהתחברות בסיסמה נדחית:

bash
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password youruser@your-lab-vm

החיבור אמור להיכשל בהודעת permission denied. את הבדיקה הזאת מריצים בעצמך על ה-VM שבבעלותך. היא לא הורצה במחשב הזה.

ה-agent ו-known_hosts

ssh-agent

הקלדת ה-passphrase בכל חיבור מתישה. ssh-agent מחזיק את המפתח המפוענח בזיכרון למשך הסשן, כך שמקלידים את ה-passphrase פעם אחת.

bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/lab_ed25519
ssh-add -l

ssh-add -l מציג את טביעות האצבע שה-agent מחזיק. במחשב ה-Windows הזה ssh-add -l רץ בלי agent פעיל והדפיס Could not open a connection to your authentication agent. עם קוד יציאה 2. ב-Windows משתמשים לזה בשירות OpenSSH Authentication Agent. מפעילים את השירות מקונסולת Services או מ-PowerShell עם הרשאות מנהל. זה שינוי במערכת שלך, ולכן עושים אותו בעצמך ורק אם רוצים שה-agent ירוץ.

agent הוא נוח, והוא גם מטרה. כל מי שיכול לדבר עם ה-socket של ה-agent בזמן שהסשן שלך פעיל יכול לבקש ממנו לחתום על דברים. לכן נמנעים מ-agent forwarding ‏(ssh -A) למארחים שאין בהם אמון מלא. משתמש root במארח המרוחק יכול להשתמש ב-agent המועבר שלך. כדי להגיע למארח פרטי דרך bastion, משתמשים ב-jump host:

bash
ssh -J youruser@bastion youruser@private-vm

known_hosts

הלקוח שומר מפתחות מארח בקובץ ~/.ssh/known_hosts, שורה אחת לכל מארח וסוג מפתח. אפשר לעשות hash לשורות עם HashKnownHosts yes, וזה מסתיר שמות מארחים ממי שקורא את הקובץ.

חיפוש מארח:

bash
ssh-keygen -F your-lab-vm

הסרת רשומה אחרי בנייה מחדש של VM וקבלת מפתח מארח חדש:

bash
ssh-keygen -R your-lab-vm

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

נקודות עיקריות

  • לעולם לא משתפים את המפתח הפרטי. רק הקובץ עם הסיומת .pub יוצא לשרתים, למארחי Git או לאנשים אחרים.
  • מגינים על המפתח הפרטי עם passphrase ושומרים גיבוי של הקובץ.
  • מאמתים את טביעת האצבע של המארח בחיבור הראשון, ובודקים כל שינוי בהמשך.

טעויות נפוצות

  • הדבקת המפתח הפרטי בצ׳אט, ב-issue, בכרטיס או בצילום מסך. צריך להתייחס אליו כאל סיסמה שאי אפשר לאפס. אם הוא דולף, יוצרים מפתח חדש, מתקינים אותו ומסירים את המפתח הציבורי הישן מהקובץ authorized_keys.
  • התקנת המפתח הפרטי על השרת במקום הציבורי. השרת צריך רק את השורה מהקובץ .pub בתוך הקובץ authorized_keys.
  • הרשאות בשרת. ב-Linux, ‏~/.ssh צריך להיות 700 והקובץ authorized_keys צריך להיות 600. הרשאות רופפות יותר יכולות לגרום ל-sshd להתעלם מהמפתח. כשהתחברות במפתח נכשלת, בודקים את הלוגים של sshd.
  • כיבוי סיסמאות לפני שהתחברות במפתח עובדת. זו הנעילה הנפוצה ביותר. עובדים לפי הסדר בשלב 6.
  • מפתח אחד לכל דבר. שימוש חוזר במפתח אחד במכונות מעבדה, במארחי Git ובמערכות פרודקשן אומר שדליפה אחת פותחת הכול. משתמשים במפתחות נפרדים לפי ייעוד, כמו lab_ed25519 למעבדה ומפתח אחר ל-GitHub.
  • קבלת מפתח מארח לא מוכר בלי בדיקה. החיבור הראשון הוא הרגע שבו הכי סביר שמתחזה ייכנס. משווים את טביעת האצבע לפני הקלדת yes.
  • אובדן ה-passphrase. אין שחזור. שומרים אותו במנהל סיסמאות.
  • שורות כפולות ב-authorized_keys. הרצת ssh-copy-id פעמיים לא מזיקה, אבל הוספה ידנית של מפתח כמה פעמים מקשה על ביקורת הקובץ. מסירים מפתחות שכבר לא בשימוש.

איך ממשיכים

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

  • הגדרות לכל מארח בקובץ ~/.ssh/config. נותנים לכל מארח כינוי, מגדירים IdentityFile ומוסיפים IdentitiesOnly yes, כדי שהלקוח יציע רק את המפתח שנבחר. כך הלקוח לא מנסה כל מפתח שב-agent מול שרת.
  • מפתחות אבטחה. OpenSSH יכול ליצור מפתחות שנשמרים על מפתח אבטחה חומרתי, עם ssh-keygen -t ed25519-sk. החלק הפרטי לא ניתן אז להעתקה מהמכשיר. לפני שמסתמכים על זה, בודקים את גרסת ה-OpenSSH ואת התמיכה של המפתח שלך.
  • תעודות SSH. ארגונים עם שרתים רבים משתמשים לעיתים קרובות ברשות תעודות במקום להפיץ מפתחות לכל מארח. כדאי להכיר את הרעיון גם אם עוד אין בו צורך.
  • קריאת מסמכי המקור. דפי ה-man של ssh-keygen ושל sshd_config מתארים כל אפשרות שנתקלים בה. RFC 4253 מסביר את שכבת התעבורה, ו-RFC 8709 מכסה את Ed25519 ב-SSH.

אם הרשאות קבצים ובעלות עדיין חדשים לך, כדאי לקרוא קודם את המאמר על קבצים והרשאות ב-Linux. המאמר הבא עוסק ברשתות Docker מבודדות למעבדות, שאפשר להשתמש בהן כדי להרחיק תעבורת מעבדה מהרשת היומיומית שלך.

מקורות

מקורות

  1. OpenBSD manual: ssh-keygen(1)
  2. OpenBSD manual: sshd_config(5)
  3. OpenSSH 9.5 release notes
  4. RFC 4253: The Secure Shell (SSH) Transport Layer Protocol
  5. RFC 8709: Ed25519 and Ed448 Public Key Algorithms for SSH

עוד בנושא Linux וכלי פיתוח

Linux וכלי פיתוח

יסודות Bash לעבודת אבטחה

pipes, הפניות, משתנים, לולאות, קודי יציאה ו-set -euo pipefail, ואז שימוש בהם כדי לספור התחברויות כושלות ולחשב hash לתיקייה.

מתחילים11 דקות קריאה

Linux וכלי פיתוח

הרשאות ב-Linux: משתמשים, קבוצות, chmod ו-umask

בעלים וקבוצות ב-Linux, ביטי rwx,‏ chmod,‏ umask ו-setuid, עם מעבדה שבודקת גישה כמשתמש שני ומוצאת הרשאות קבצים מסוכנות.

מתחילים10 דקות קריאה