טיפ: להפריד אתרים

הערה: כפרילאנסר (שמחפש עבודה, תמיד. קורות חיים כאן), אני נתקל בכל מיני דברים שאנשים לא מכירים או לא הכירו, ופוסטים כמו הפוסט הנ"ל בא לסייע לאלו שלא מכירים את התחום. אם יש לכם רעיונות לפוסטים חדשים, אשמח לשמוע מכם.

רבים מבוני האתרים ששוכרים שרת VPS (או שרת יעודי) לאחסן אתרים שונים שלהם, מבצעים טעות רצינית כשהם מאחסנים את האתרים. הטעות הזו יכולה לגרום לכך שפורצים משועממים יכולים להשחית חלק או רוב או את כל האתרים באותו שרת מבלי להתאמץ יותר מדי. ההשחתה היא במקרה הטוב, פריצה וגניבת ה-DB ואיפוס סיסמאות הן דבר שאני לא מאחל לאף אחד, אך זה יכול לקרות כשלא משתמשים בכלים הנכונים.

רבים מאותם בוני אתרים אינם מכירים לינוקס בצורה מספקת והן מאחסנים את האתר במיקום ברירת מחדל כמו var/www/html/ (במערכות מבוססות CentOS) או var/www/ בהפצות כמו Debian או Ubuntu. מכיוון ששרת ה-Web (במקרה המדובר לפוסט זה מדובר בשרת Apache) משתמש במשתמש משלו (apache במקרה של CentOS, ו-www-data במקרה של Ubuntu/Debian), בוני אתרים רבים משנים הרשאות של קבצים על מנת שיתאימו ולעיתים הם פותחים יותר מדי הרשאות (כמו הרשאות כתיבה/קריאה/הרצה לכל משתמש), מה שיעשה את חייו של הפורץ קלים מאוד.

באופן עקרוני, שרת Apache יודע לעבד קבצי HTML, JS וקבצי CSS ומספר קבצים המיועדים להגדרות Apache כמו htpasswd, htaccess ועוד. שאר סוגי הקבצים (כמו PHP ושפות אחרות) מצריכים מודולים שיודעים להתממשק עם שרת אפאצ'י והגדרות שכאשר השרת נתקל בקובץ מסוג PHP לדוגמא, המודול של PHP בשרת אפאצ'י ידע לעבד את הקובץ ואת הפלט הוא מעביר לשרת אפאצ'י לשליחה לדפדפן. השיטה הזו היא השיטה הסטנדרטית שמגיעה עם כל הפצת לינוקס והיא עובדת טוב, רק שיש לה בעיה מרכזית אחת והיא: כל הקבצים נגישים לאפאצ'י ואם מישהו מצליח להשתלט על שרת האפאצ'י, הוא יכול לעשות נזקים בכל האתרים עם אותו User גם כשלמשתמש Apache אין הרשאות Shell (הוא יכול להריץ דפי PHP? זה יספיק לפורץ).

הפתרון הטוב ביותר לדברים כאלו היא הפרדת אתרים ומשתמשים, כאשר לכל אתר יש משתמש וקבוצה משלו (אין צורך שהם יהיו תחת קבוצת apache או www-data, תיכף נגיע לזה). במצב רגיל אם ננסה לעשות זאת ונייצר קובץ VirtualHost המורה לשרת אפאצ'י כי אתר X.COM נמצא ב- home/x.com/ סביר להניח שנקבל הודעת Forbidden מהדפדפן ואז נצטרך לשייך את ה-User לקבוצת ה-apache (או www-data), נצטרך לפתוח הרשאות קריאה והרצה לקבוצת Apache בנוסף להרשאות כתיבה/קריאה/הרצה וגם אז תיתקלו בבעיה שאינכם יכולים להעלות קבצים דרך מערכות CMS (כמו ג'ומלה/דרופל/וורדפרס) אלא דרך FTP ולקינוח – עדיין הבעיה הראשית (של פורץ שמשתלט על משתמש apache) לא נפתרת. צריך פתרון לכך.

הפתרון שאכיר לכם הפעם נקרא SuPHP ומה שהאפליקציה הזו עושה די פשוט: את קבצי ה-PHP שלכם האפליקציה הזו תנתב בצורה אחרת, כאשר שאר הקבצים שאפאצ'י יודע באופן טבעי לנהל – הוא (ה-apache) ינהל. כך, כשהמשתמש נכנס לאתר ויש צורך לעבד את דף index.php ה-suphp יפנה את הדף לאפליקציה שנקראת php-cgi שתעבד את הדף תחת המשתמש שיצרתם (לא תחת משתמש apache. השיטה ש-SuPHP עובד היא גם ששיטה שכלים אחרים דומים עובדת (כמו SuEXEC ואחרים)) והפלט יוגש לאפאצ'י לשליחה לדפדפן. כך אם יצרנו משתמש בשם shluk שמאחסן את אתר x.com ומישהו פורץ לאתר x.com – הפורץ יוכל להשחית את אתר x.com אך לא את אתר y.com שיושב באותו שרת תחת שם משתמש אחר.

אז איך מבצעים זאת, די פשוט. ראשית יש להתקין 2 חבילות: mod_suphp וחבילת php-cli (זה תחת CentOS, תחת Ubuntu אפשר לראות כאן. החיים עם CentOS יותר קלים 🙂 )

לאחר ההתקנה נערוך (כ-root כמובן) את קובץ etc/suphp.conf/ (שוב, באובונטו השם קצת שונה והוא etc/suphp/suphp.conf/ ) – להלן דוגמא של קובץ שלי:

[global]
logfile=/var/log/httpd/suphp_log
loglevel=info
webserver_user=apache
docroot=/
env_path=/bin:/usr/bin
umask=0077
min_uid=500
min_gid=500

; Security options
allow_file_group_writeable=false
allow_file_others_writeable=false
allow_directory_group_writeable=false
allow_directory_others_writeable=false

;Check wheter script is within DOCUMENT_ROOT
check_vhost_docroot=true

;Send minor error messages to browser
errors_to_browser=false

[handlers]
;Handler for php-scripts
"x-httpd-php="php:/usr/bin/php-cgi"

;Handler for CGI-scripts
"x-suphp-cgi="execute:!self"

10 השורות הראשונות הן הגדרות כלליות, כמו היכן ה-Log של SuPHP ישב, מה תהיה רמת הדיווח (בתור התחלה השאירו אותו כ-info ואם הכל עובד שנו אותו ל-warn או error), מהו המשתמש שמריץ את שרת האפאצ'י, ההרשאות שצריך שיהיו לקבצי php, מהו המספר המנימלי ל-UserID ו-GroupID (חשוב אם יש לכם מספר משתמשים וחלקן נמצאים בקבוצות משותפות).

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

החלק השלישי נועד לחסום אפשרות להריץ קבצי php שלא נמצאים ב-DocumentRoot שהגדרתם.

החלק הרביעי אומר ל-SuPHP האם להציג את השגיאות בדפדפן (יחד עם תוכן האתר) או לא. אם זו מערכת פרודקשן, מומלץ שלא יציג. אם זו מערכת טסטים, יש לשנות את ה-false ל-true

החלק החמישי הוא חלק של ניהול, התכל'ס עצמו. מי יריץ את קבצי ה-php? אפליקציה שנקראת php-cgi שהיא תרוץ תחת המשתמש שנגדיר ולא כמשתמש apache. החלק האחרון הוא מי יריץ את suphp – וכפי שאתם רואים, הוא יריץ את עצמו.

עד כאן החלק של SuPHP עצמו, עכשיו יש צורך להגדיר את ה-VirtualHost של האתר עצמו, להלן דוגמא:

NameVirtualHost *:80

<VirtualHost *:80>
      ServerName x.com
        ServerAdmin [email protected]
        DocumentRoot /home/x/public_html
        ErrorLog /var/log/httpd/x-error.log
        CustomLog /var/log/httpd/x-access.log combined
        LogLevel warn
        suPHP_Engine on
        AddHandler x-httpd-php .php
        suPHP_AddHandler x-httpd-php
     suPHP_UserGroup xcom xcom
</VirtualHost>

השורה הראשונה היא חשובה באופן כללי אם יש לכם מספר אתרים. צריך שהיא תופיע באחד מקבצי ההגדרות VirtualHost של האתרים שלכם (ואגב, טעות נפוצה שהרבה עושים – שהם מכניסים את כל ההגדרות לקובץ httpd.conf – טכנית בשביל זה ב-CentOS יש תיקיה שנקראת conf.d ובה מומלץ לשים כל אתר בקובץ עם סיומת conf נפרד).

החלק הרלוונטי הוא החלק המודגש:

שורה ראשונה – אנחנו מפעילים את המנוע SuPHP

השורה השניה היא אופציונאלית ואפשר להעיף אותה (הרגל מגונה שלי, אבל ג'אסט אין קייס) – היא מציינת שקבצים שמסתיימים ב-php. ינוהלי ע"י SuPHP

שורה שלישית אומרת לאפאצ'י שכל מה שקשור ל-php עצמו – ינוהל על ידי SuPHP

שורה רביעית אומרת מיהו המשתמש וקבוצת המשתמש שהקובץ ירוץ תחתיו

אחרי שסיימנו עם ההגדרות, אפשר להפעיל מחדש את שרת Apache (פקודת service httpd restart). במקרה וזה שרת פרודקשן, מומלץ פשוט לבצע reload מבלי להפסיק את השרת (service httpd reload)

עכשיו נגיע לחלק החשוב והוא התיקיה שבה יאוחסנו הקבצים. בד"כ התיקיה הזו נמצאת תחת המחיצה home. 

ההרשאות שלה צריכות להיות מצומצמות לכתיבה/קריאה/הרצה ע"י המשתמש עצמו והרצה בלבד ע"י אחרים. זה נראה כך:

drwx-----x  4 xcom xcom 4096 Mar  3 20:52 x.com

ה-x האחרון יאפשר לשרת Apache להריץ קבצים, אך לא לכתוב (אין לנו צורך שהוא יכתוב). על מנת לשנות את ההרשאות לתיקיה, יש צורך בפקודה chmod 701 x.com (תחליפו את ה-x.com בשם התיקיה). שאר הקבצים בתוך התיקיה יכולים להיות עם הרשאות קריאה/כתיבה למשתמש, קריאה בשאר (644) והתיקיות עצמן קריאה/כתיבה/הרצה למשתמש, קריאה והרצה לשאר (755). למי שסקרן לגבי ה-701 – מה שזה עושה (בניגוד ל-755) זה חוסם את האפשרות שמשתמש אחר יוכל לראות מה יש בתוך התיקיה של משתמשים אחרים.

כפי שציינתי, SuPHP הוא רק פתרון אחד. יש פתרונות אחרים כמו SuEXEC או FastCGI (כאשר FastCGI הרבה יותר מהיר מ-SuPHP) אך הם עובדים פחות או יותר באותה צורה וגם ההגדרות אינן שונות משמעותית. יחד עם זאת לשיטות אלו ישנו חסרון שצריך לקחת בחשבון והוא פניה בכל דף PHP להרצת תהליך חיצוני (בניגוד ל-DSO, מה ש-PHP עושה במצב ברירת מחדל), ולכן מומלץ לשים פתרון Cache על מנת לפתור בעיה זו.

Print Friendly, PDF & Email

2 תגובות בנושא “טיפ: להפריד אתרים

  1. אני בדיוק באמצע לכתוב מאמר על הפרדת אתרים בשרת.

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

  2. אני משתמש כבר מספר שנים בפתרון מבוסס fast-cgi לזה (יחד עם lighttpd). בגדול לכל אתר יש user משלו ומוגדר לו socket נפרד שמתקשר עם תהליכים של php מעל fast-cgi (בהתאם לעומס על כל אתר). ברקע אני מריץ תהליכים של php-cgi להקשיב על כל סוקט עם הרשאות בהתאם לכל אתר (בגדול משנה את ה-userid).

    אולי הגיע הזמן שאני אשחרר את השינוים שלי לסקריפטי אתחול של lighttpd שמטפלים בזה.

סגור לתגובות.