איך אתר עובד עם מסד נתונים - PHP ו-SQL¶
הרבה מאתרי האינטרנט שאתם מכירים - מערכות ניהול תוכן, חנויות אונליין, פורומים - בנויים על אותה נוסחה בסיסית - שפת שרת שמריצה לוגיקה, ומסד נתונים ששומר את המידע. אחד הצירופים הנפוצים והוותיקים ביותר לשילוב הזה הוא PHP יחד עם SQL. כדי להבין איפה חולשות ווב נולדות, כדאי קודם להבין בדיוק איך הצירוף הזה עובד כשהכל תקין.
שלב ראשון - המשתמש שולח טופס¶
תארו לכם עמוד התחברות פשוט - שדה שם משתמש, שדה סיסמה, וכפתור כניסה. כשהמשתמש לוחץ על הכפתור, הדפדפן שולח בקשת HTTP לשרת, ובתוכה הערכים שהוקלדו בטופס. עד כאן זה בדיוק מה שתיארנו בפוסטים אחרים על מבנה בקשת HTTP - זה פשוט מידע גולמי שעובר מהדפדפן לשרת.
שלב שני - PHP מקבל את הבקשה ומעבד אותה¶
בצד השרת, קובץ PHP מקבל את הבקשה הזאת, וקורא מתוכה את הערכים ששלח המשתמש. PHP היא שפת תכנות שנועדה במיוחד לרוץ בצד השרת ולייצר תוכן דינמי - במקום קובץ HTML קבוע, יש קוד שרץ בכל בקשה ובונה את התשובה בהתאם למה שהתקבל. בשלב הזה, ה-PHP צריך להחליט מה לעשות עם הנתונים - במקרה שלנו, לבדוק מול מסד הנתונים אם שם המשתמש והסיסמה נכונים.
שלב שלישי - בניית שאילתת SQL¶
כאן PHP בונה שאילתה - משפט בשפת SQL שאומר למסד הנתונים בדיוק מה לחפש. שאילתה כזאת יכולה להיראות כך:
ה-PHP מכניס לתוך המשפט הזה את הערכים שהמשתמש שלח, ושולח את השאילתה השלמה למסד הנתונים.
שלב רביעי - מסד הנתונים מריץ ומחזיר תוצאה¶
מסד הנתונים, לרוב MySQL או MariaDB בעולם ה-PHP, מריץ את השאילתה מול הטבלאות שלו, ומחזיר תוצאה - שורה שמתאימה לתנאי, או כלום אם אין התאמה. PHP מקבל את התוצאה הזאת בחזרה, ומחליט מה לעשות איתה - להתיר כניסה, או להציג הודעת שגיאה.
שלב חמישי - בניית העמוד והחזרתו לדפדפן¶
לבסוף, PHP בונה עמוד HTML שמשקף את התוצאה - למשל, מסך "ברוכים הבאים" אם ההתחברות הצליחה, או חזרה למסך ההתחברות עם הודעת שגיאה אם לא. העמוד הזה חוזר בתשובת HTTP לדפדפן, שמציג אותו למשתמש. כל התהליך הזה, מלחיצה על כפתור ועד עמוד חדש על המסך, קורה תוך שבריר שנייה.
אז איפה נכנסת הבעיה¶
השלב הכי קריטי בכל התהליך הזה הוא שלב שלוש - איך בדיוק הערכים שהמשתמש הזין נכנסים לתוך משפט ה-SQL. אם ה-PHP פשוט "מדביק" את הטקסט שהמשתמש הקליד ישירות לתוך השאילתה, בלי שום טיפול, אז המשתמש בעצם לא רק ממלא נתונים - הוא משפיע על המבנה של הפקודה עצמה. זו בדיוק הדלת שממנה נולדת חולשת SQL Injection, שכבר הרחבנו עליה בפוסט נפרד. לא ניכנס כאן לפרטי הניצול, אבל חשוב להבין את השורש - ברגע שקלט משתמש מתערבב עם קוד השאילתה בלי הפרדה ברורה, יש בעיה.
הפתרון - Prepared Statements¶
הדרך הנכונה לבנות שאילתה כזו היא באמצעות Prepared Statements, שאילתות מוכנות מראש. השיטה הזאת מפרידה לגמרי בין מבנה השאילתה לבין הנתונים - קודם מגדירים את מבנה השאילתה עם מקומות שמורים לערכים, ורק אחר כך "מזינים" אליה את הערכים עצמם, כשמסד הנתונים כבר יודע להתייחס אליהם רק כטקסט ולא כחלק מהפקודה. ב-PHP זה נעשה בקלות יחסית באמצעות ספריות כמו PDO או mysqli, ואין באמת סיבה טובה לכתוב שאילתות בצורה אחרת היום.
הבנה של הזרימה הזאת - מטופס, דרך PHP, אל מסד הנתונים, וחזרה - היא בדיוק הבסיס שעליו בונים בקורס פריצת אתרים למתחילים, לפני שעוברים לתקוף חולשות אמיתיות באתר שבניתם בעצמכם.
יש לכם שאלות על התהליך הזה, או רוצים לדבר עם אנשים שבונים ולומדים בדיוק את זה? מוזמנים להצטרף אלינו.
לסיכום¶
מאחורי כל טופס פשוט באתר עומד תהליך מסודר של תקשורת בין PHP למסד נתונים - בקשה, בניית שאילתה, הרצה, ותשובה. ההבנה של התהליך הזה היא לא רק ידע כללי, היא הבסיס שממנו אפשר להבין למה טיפול לא זהיר בקלט משתמש הוא אחת הטעויות הנפוצות והמסוכנות ביותר בפיתוח ווב.