SSD Nodes Learn Hosting plans →
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-31

הרצת שירותים כמשתמש ללא הרשאות root

הרצת שירות כ-root הופכת באג פשוט לפרצת אבטחה קריטית. למדו כיצד להגביל גישה באמצעות יצירת משתמש ייעודי לכל שירות או שימוש בהגדרה DynamicUser ב-systemd להגנה מרבית.

מדוע לא להריץ הכול כ-root

למשתמש root יש הרשאות מלאות על המכונה: הוא יכול לקרוא כל קובץ, לשנות כל הגדרה ולמחוק את המערכת כולה. כאשר מריצים שירות כ-root, מעניקים את כל הכוח הזה לשירות עצמו. אם בשירות קיים באג שניתן לנצל, התוקף לא מקבל רק שליטה על השירות, אלא שליטה על ה-root, ומשמעות הדבר היא שליטה על השרת כולו. הרצת שירות כמשתמש ללא הרשאות מיוחדות מגבילה את הנזק. באג בשירות שרץ תחת חשבון מוגבל מעניק לתוקף גישה רק למה שאותו חשבון יכול לגשת אליו, מה שאמור להיות כמעט שום דבר.

זהו עקרון ההרשאה המינימלית (principle of least privilege): העניקו לכל חלק במערכת בדיוק את הגישה הדרושה לו לביצוע תפקידו, ולא מעבר לכך. זהו ההרגל האפקטיבי ביותר להגבלת היקף הנזק במקרה של פריצה, ובשרת מודרני יישומו אינו כרוך כמעט במאמץ.

חשבון ייעודי לכל שירות

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

sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvc

לכל flag יש חשיבות. --system הופך אותו לחשבון שירות ולא לחשבון משתמש אנושי. --no-create-home מדלג על יצירת ספריית בית שאינה נחוצה. --shell /usr/sbin/nologin מבטיח שגם אם תוקף ישיג גישה לחשבון, הוא לא יוכל לפתוח באמצעותו shell. החשבון קיים אך ורק כדי להיות בעלים של תהליך ושל הקבצים שלו.

לאחר מכן, העניקו למשתמש זה רק את הקבצים להם הוא זקוק, ולא מעבר לכך:

sudo chown -R appsvc:appsvc /opt/myapp

כעת השירות קורא וכותב בספרייה שלו בלבד ואין לו גישה לשום מקום אחר בדיסק. אם השירות ייפרץ אי פעם, הקבצים שהתוקף יוכל לשנות מוגבלים ל-/opt/myapp; החשבון עדיין יכול לקרוא כל קובץ שפתוח לקריאה לכלל המשתמשים, אך הוא אינו יכול לשנות את שאר המערכת.

הגדרת הרצת השירות תחת משתמש ספציפי ב-systemd

לאחר יצירת החשבון, יש להורות ל-systemd להריץ את השירות תחתיו. בקובץ ה-unit, שורה אחת מבצעת זאת:

[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvc

User=appsvc משמעותו שהתהליך מתחיל עם הרשאות מוגבלות של אותו חשבון במקום עם הרשאות root. זוהי הדרך התקנית והמקובלת להרצת יישום תחת systemd, ומומלץ ליישם זאת עבור כל שירות שעבורו אתם כותבים קובץ unit. עם זאת, ויתור על הרשאות לא יועיל אם systemd עוקב אחר התהליך הלא נכון; לכן, אם ה-unit מדווח על מצב active לאחר שה-daemon קרס בשקט, ודאו ש-בחרתם את ה-Type= המתאים לאופן שבו התהליך שלכם עולה.

או דלגו על ניהול חשבון משתמש לחלוטין בעזרת DynamicUser

systemd יכול להרחיק לכת עוד יותר וליצור עבורכם משתמש זמני, כזה שקיים רק כל עוד השירות פועל. הגדירו את DynamicUser=yes ולא תצטרכו לנהל חשבון משתמש כלל:

[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myapp

בעת ההפעלה, systemd מקצה מזהה משתמש (UID) פנוי; בעת העצירה, הוא משחרר אותו. השירות מקבל גם /tmp פרטי, תצוגה לקריאה בלבד של רוב מערכת הקבצים, וספריית מצב (state directory) לכתיבה תחת /var/lib/myapp, ש־StateDirectory= מגדיר ומעביר לשירות. שום דבר מזה לא היה אפשרי תחת SysV init, שם הורדת הרשאות הושארה לשיקול דעתו של כל סקריפט הפעלה של שירות, ופער זה הוא חלק משמעותי מ-הסיבה לכך שהפצות עברו ל-systemd מלכתחילה. עבור שירות עצמאי שזקוק רק לספריית מצב משלו, DynamicUser=yes הוא הדרך בעלת המאמץ המינימלי להשגת בידוד חזק, כיוון שאין חשבון בעל קיום ארוך טווח שתוקף יכול לנסות לנצל.

כתיבת יחידות (units) באופן ידני היא פעולה עדינה, והערך המוסף העיקרי הוא הגדרת הנחיות האבטחה בצורה נכונה. המחולל ב-מדריך ה-systemd service and timer יכול למלא עבורכם את האפשרויות הללו כך שהיחידה תהיה תקינה כבר מהפעם הראשונה.

כיצד זה משתלב עם שאר המערכת

עקרון ה-least privilege הוא שכבה אחת, והוא פועל לצד השכבות האחרות ולא מחליף אותן. חומת אש מסוג default-deny שולטת על מה שיכול להגיע לשירות; הרצת השירות כמשתמש ללא הרשאות מיוחדות מגבילה את מה שהשירות יכול לבצע במקרה של פריצה; ו-הקשחת SSH מונעת מתוקפים גישה לשרת מלכתחילה. אף אחד מאלה אינו מספיק לבדו, אך יחד הם מבטיחים שבאג בשירות אחד לא יהפוך לפריצה לכל השרת. אירוח שירות המגן על סודות מדגים היכן השכבות הללו נעצרות: חשבון מוגבל מגביל את מה שתהליך פרוץ יכול לגשת אליו, אך מנהל סיסמאות בניהול עצמי כמו Vaultwarden עדיין תלוי באופן שבו אתם מגנים על ה-admin token ועל קובץ הגיבוי שלו, שכן בידוד משתמשים אינו מכסה היבטים אלו.

לפני שתמשיכו, עברו על רשימת תיוג להקשחת השרת כולו והפיקו עותק מותאם אישית לעבודה:

ToolVPS hardening checklist

FAQ

מדוע לא כדאי להריץ שירות כ-root?

מכיוון ש-root יכול לבצע כל פעולה במכונה, שירות שרץ כ-root ונפרץ מעניק לתוקף שליטה על השרת כולו, ולא רק על השירות. הרצת השירות תחת חשבון מוגבל ונטול הרשאות מצמצמת את הנזק למה שאותו חשבון יכול לגשת אליו. שמרו את root לניהול המערכת, והריצו כל שירות שפועל לאורך זמן כמשתמש מוגבל.

כיצד יוצרים משתמש שאינו יכול להתחבר למערכת?

הריצו את sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME. ה-shell מסוג nologin מבטיח שהחשבון לא יוכל לפתוח session אינטראקטיבי גם אם פרטי הגישה שלו נגנבו, --system מסמן אותו כחשבון שירות, ו---no-create-home מדלג על יצירת ספריית בית שאינה נחוצה לו. העניקו לו בעלות על הקבצים שלו בלבד באמצעות chown.

מהו DynamicUser ב-systemd?

ההגדרה DynamicUser=yes מורה ל-systemd ליצור משתמש זמני עבור השירות שקיים רק בזמן שהשירות רץ, כך שאין צורך לנהל חשבון קבוע. היא גם מעניקה לשירות /tmp פרטי, תצוגת מערכת קבצים שרובה לקריאה בלבד, וספריית מצב (state) מנוהלת. זו הדרך הקלה ביותר להריץ שירות עצמאי תחת זהות חד-פעמית ובעלת הרשאות נמוכות.

האם הרצה כמשתמש שאינו root מחליפה firewall?

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

אילו קבצים צריכים להיות בבעלות משתמש השירות?

רק הקבצים שהשירות באמת צריך, ולא מעבר לכך. העניקו לחשבון בעלות על ספריית העבודה שלו ועל הנתונים שלו, והשאירו את כל השאר בבעלות root. תבנית עבודה טובה היא sudo chown -R svc-app:svc-app /opt/svc-app עבור ספריית היישום, בעוד שהגדרות תחת /etc נשארות בבעלות root וניתנות לקריאה בלבד על ידי השירות. המטרה היא שאם התהליך ייפרץ אי פעם, הקבצים שהוא יוכל לשנות יוגבלו לנתונים שלו בלבד, ולא לשאר המערכת.

#security#least-privilege#systemd#users#hardening#linux