שימוש בטכניקת Salt על מנת להגן על סיסמאות

הסבר על שימוש בטכניקה לשמירת ססמאות במסד נתונים עם דוגמאות ב-PHP.

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

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

אני לא הולך להרחיב את הדיבור על המשתמשים אלא יותר על המתכנתים והאחריות שלהם. איך אנו יכולים למנוע שימוש לרעה בנתוני המשתמשים אם האתר שלנו ייפרץ? מערכת אבטחה טובה של אתר בנויה מכמה מעגלים. המעגל הראשון הוא דאגה שהאתר לא ייפרץ – לאחסן אותו בספק נורמלי ואם הוא לא מאוחסן ב-shared אז לדאוג להתקנת עידכוני אבטחה על השרת. המעגל השני הוא לכתוב מנגנון אבטחה טוב – לבצע סניטציה של נתוני משתמש, למנוע התקפות XSS וכו' וכו'. המעגל השלישי שבו נדון כעת הוא שמירה והגנה על מסד הנתונים גם לאחר שהאתר נפרץ.

למה זה חשוב? בוא ונניח שיש לי אתר, נגיד אתר לוחות בשם homemore.co.il. שבו יש לי טבלה בשם users. הטבלה נראית כך:


+---------+-----------+------------+---------------------+
| idusers | user_name | password   | mail                |
+---------+-----------+------------+---------------------+
|       1 | ran       | birthday16 | [email protected]       |
|       2 | moshe_r   | qwertyuiop | [email protected] |
|       3 | avico     | q1w2e3     | [email protected]   |
+---------+-----------+------------+---------------------+

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

איך נמנעים מזה? שימו לב לאותה טבלה, אך הפעם מאובטחת יותר.


+---------+-----------+----------------------------------+---------------------+
| idusers | user_name | password                         | mail                |
+---------+-----------+----------------------------------+---------------------+
|       1 | ran       | 2f0007585e5d4584adf91fe11ab16db7 | [email protected]       |
|       2 | moshe_r   | 6eea9b7ef19179a06954edd0f6c05ceb | [email protected] |
|       3 | avico     | 7cbb3252ba6b7e9c422fac5334d22054 | [email protected]   |
+---------+-----------+----------------------------------+---------------------+


מה עשיתי? העברתי את הסיסמה באמצעות מנגנון הצפנה שנקרא md5. ההצפנה הזו אמורה להיות חד כיוונית – ברגע שאני מבצע הצפנת md5 אני לא יכול לקחת את המחרוזת שהתקבלה ולהחזיר אותה לסיסמה המקורית. ככה עושים את זה ב-PHP:


$hash = md5($password);

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

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


$salt1 = 'randomstring!@#(';
$salt2 = 'anotherrandomstring@#E!;
$hash = md5($salt1.$password.$salt2);

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


$salt1 = 'randomstring!@#(';
$salt2 = 'anotherrandomstring@#E!';
$salt3 = 'thirdrandomstring%^&';
$hash = md5(md5($salt1.$password.$salt2)+$salt3);

מדובר בטכניקה מקובלת ובדוקה באבטחת מידע. יש כאלו שגם מצפינים את שם המשתמש. ניתן וצריך להצפין כל נתון שמשמש לאותנטיקציה חד כיוונית. האלגוריתמים של ה-salt שאפשר להשתמש בהם הם רבים מאד ודוגמאות יפות אפשר למצוא ב-php.net. אבל מה שחשוב הוא להשתמש בהצפנה ולא להגיע למצב שסיסמה נמצאת באופן גלוי בטבלה. לא רק שזה רע למשתמשים – זה חושף את המתכנת לתביעה (מוצדקת) על רשלנות.

פוסטים נוספים שכדאי לקרוא

גלילה לראש העמוד