עדכון לפוסט: התווספו שיטות נוספות מומלצות, תודה למגיבים בטוקבקים.
ביום ה' האחרון נודע כי אתר "תפוז" נפרץ, ובסיס הנתונים שהכיל את פרטי המשתמשים (כמו אימייל, סיסמאות וכו') נפרץ. פריצה זו מצטרפת לשורת פריצות באתרים שונים, ויש אתרים הרבה יותר גדולים שנפרצים ופרטי המשתמשים מופצים לכל עבר (ומי שעושה מזה הכי הרבה הם הספאמרים כמובן, עוד כמה מיליוני רשימות לדחוף להם ויאגרה מזוייפת, ועוד כל מיני שקרים).
הבעיה העיקרית בד"כ של אותם אתרים, זה שאותם מתכנתים באותה חברה, נמצאים תחת אשליה שאם יש את הקופסאות XYZ שנותנים כל מיני סוגים של "חומות אש", אז הם מוגנים ואפשר לשים פס גדול על כל עניין של אבטחת מידע, המלחת סיסמאות וכו'. בד"כ אני קורא לזה במובן הכי פשוט מתכנתים עצלנים.
אבל זה לא קורה רק אצל אתרים גדולים, זה קורה גם באתרים בינוניים וקטנים, כאלו שלא תשמעו עליהם או כאלו שאולי תשתמשו בהם ולא תדעו שהפרטים שלכם חשופים. זוכרים את "הפורץ הסעודי"? (כן, הוא כבר מת), זה שפרץ לאתרים שונים ופירסם מספרי כרטיסי אשראי, מה שהכניס את חברות האשראי בארץ לסרטים ובמיוחד את לקוחותיהם? אז כן, הבעיה גם שם.
והיא קשורה בד"כ לעצלנות נטו או לתחושה של "הכל בסדר" בגלל הבטחות שניתנות ע"י ספקי אחסון שונים ש"הכל מוגן". כמובן שאין חיה כזו
אז לטובת המפתחים שמכירים חלקית את נושא ההמלחה והצפנה, ולטובת אלו שלא מכירים, הנה שיעור מזורז. אני מדבר בפוסט זה על MySQL אבל זה רלוונטי לכל אפליקציית בסיס נתונים.
באופן עקרוני, תוכנת בסיסי נתונים (אני פשוט אקרא לזה DB בפוסט זה) יודעות לאחסן סיסמאות בצורה מוצפנת, אבל ההצפנה עצמה מאוד קלה לפריצה. כך לדוגמא כשמשתמשים בפונקציית Password ב-MySQL כדי להכניס משתתמשים לטבלת משתמשים ב-MySQL כבר עושים את הטעות הראשונה. כפי ש-MySQL כותבים בעצמם, זה לא מיועד לניהול משתמשים עבור האפליקציה שלך, אלא עבור התחברות והתממשקות ל-MySQL.
כשרוצים להוסיף משתמשים לאפליקציה שלך, צריכים לבצע מספר שלבים:
השלב הראשון לאחר קבלת פרטי המשתמש, הוא "להמליח" את הסיסמא ומומלץ גם את כתובת האימייל. ב"המלחה" הכוונה להוסיף מספר תווים רנדומלי לפני, או אחרי, או באמצע הקלט שקיבלת, כך שאם הסיסמא שהזנתי היא hello123 אז לאחר ההמלחה היא תהיה hello123#O2j!d%425 (כאשר אחרי ה-3 יהיו ג'יבריש של אותיות רנדומליות שהמערכת תחשב מחדש בכל פעם שמישהו נרשם. אפשר לשפר ולהוסיף ג'יבריש בגדלים שונים [אנחנו פה לאמלל את חיי הפורץ או לא?], ואפשר לשים את הג'יבריש לפני הסיסמא האמיתית [כל עוד היא בגודל קבוע, כדי שתוכלו אחר כך לוודא שהסיסמא תקינה] או באמצע, הכל תלוי בכישורי התכנות של המפתח.
עכשיו, לפני שאנחנו מכניסים את הסיסמא עם הג'יבריש, אנחנו נצפין את הסיסמא עם הג'יבריש יחד. יש כל מיני סוגי הצפנות, אני ממליץ ללכת על AES-256 (חובבי PHP – יש כאן דוגמא). בשיטת הצפנה זו, ישנו מפתח שלכם, ואיתו אתם מצפינים. ההצפנה מומלץ שתיעשה דרך האפליקציה שלכם והמפתח שלא ישב בקוד עצמו אלא במקום םאחר מחוץ לתיקיות הקוד עם הרשאות מצומצמות מאוד. מדוע AES-256? כי זו הצפנה חזקה מאוד מצד אחד, ומצד שני היא לא מכבידה על שרת האפליקציות (כל שרת עם מעבד Xeon מסידרה 5XXX או מעבד i5 ומעלה או כל מעבד של AMD מה-3 שנים האחרונות כולל קידוד ופתיחת AES על הסיליקון עצמו)
אחרי שהצפננו על שרת האפליקציה את הסיסמא המומלחת, אז נוכל לכתוב את הפלט לתוך ה-DB. כך גם נעשה בצורה הפוכה כשמשתמש יתחבר למערכת ונוודא שסיסמתו נכונה.
נקודה חשובה: אם אתם עובדים דרך command line בהתממשקות ל-DB שלכם, תוודא שכשאתם יוצאים, למחוק את קובץ ההיסטוריה. אני מכיר לפחות מקרה אחד שמתכנת הצפין את הכל, אבל שכח שהמפתח שלו היה גם בקובץ היסטוריה ומי שפרץ תפס שהמפתח שם וכל ההצפנה לא ממש עזרה (בגלל זה אני ממליץ לעשות הצפנות רק בקוד שלכם, לא ישירות על ה-DB).
שיטה נוספת היא שיטת ה-Hashing – בשיטה זו אלגוריתם (כמו SHA256) מקבל טקסט כלשהו (כמו סיסמא) והוא פולט מחרוזת שנראית כמו ג'יבריש. הסיסמא עצמה לא נשמרת בשום מקום ולא נכתבת לדיסק הקשיח של השרת. מה שכן נכתב ל-DB הוא הפלט, או כפי שהוא נקרא – ה-Hash. כך כשהמשתמש מנסה להתחבר ומקיש סיסמא, הסיסמא שהוא מקיש גם עוברת את אותו תהליך ואם ה-Hash שנוצר מהסיסמא שהמשתמש זה עתה הקיש שווה ל-Hash שנמצא ב-DB, אז הסיסמא היא נכונה והמשתמש יוכל להיכנס. חשוב לציין – גם כאן ישנם אתרים רבים שמאפשרים לכל מיני פורצים להוריד טבלאות Hash מוכנות, כך שהפורץ יוכל עם GPU חזק וטבלאות – לנסות לפרוץ את ה-DB אחרי שהוא העתיק אותו ולכן חובה להוסיף לאחר הסיסמא ג'יבריש רנדומלי באורך קבוע (נניח 10-20 סימנים שמיוצרים ע"י פונקציית RAND) ולקזז את האורך הזה בקלט הסיסמא שנקלטת מהמשתמש, ואז להריץ פונקציית Hash לפי האלגוריתם שבחרתם. תוכלו לקבל פרטים נוספים ודוגמאות קוד בשפות שונות כאן. שיטה זו היא מעולה לאתרים מסויימים אך ישנם חברות שרוצות דווקא לשמור את הסיסמא עצמה, כך ששיטה זו לא תתאים להן ולכן חשוב לבדוק מה הלקוח רוצה.
אפשרית שלישית נוספת היא לוותר על עניין ההזדהות ה"עצמית" (כלומר שהאתר שלך שיזהה את המשתמש), והישענות על שרתים כמו של גוגל או פייסבוק או טוויטר וחברות אחרות, כך כשהמשתמש ירצה להיכנס, הוא יזין לתוך חלק מיוחד באתר (חלק שלא מגיע מהאתר שלכם אלא מאתר אותה חברה שבחרתם) את שם המשתמש והסיסמא שלו, והאותנטיקציה של אותה חברה תחזיר לכם אישור אם המשתמש והסיסמא נכונים וכן את פרטי המשתמש (שם פרטי, כתובת מייל וכו'). בשיטה הזו אין לכם צורך באחזקת סיסמאות (זולת סיסמאות התחברות ל-DB ולניהול המערכת), אך החסרון העיקרי של שיטה זו הוא שבאתרים רבים אנשים מעוניינים להגיב שלא בשמם/כינוי שלהם אלא להגיב בצורה אנונימית, וכאן אתם צריכים להחליט אם להכריח משתמש להתחבר עם הפייסבוק/טוויטר/גוגל שלו או לתת לו גם אפשרות להירשם דרך המערכת שלכם על מנת להגיב.
חשוב לזכור משהו אחד: רוב הפורצים למערכות אינם מתכנתים עם נסיון עשיר. הם Script kiddies שמשתמשים בסקריפטים מוכנים שהורידו או שהם "שיפצו" פה ושם איזה סקריפט שהורידו. הם ידעו איך להיכנס לשרת ה-DB שלכם ואולי אפילו להיכנס לשרתי אפליקציה שלכם, אבל בחיטוט ולימוד הקוד הם לא מי יודע מה, מה עוד שהם רוצים להתנתק כמה שיותר מהר כדי לא להיתפס. פה בדיוק החלק שאתם יכולים לאמלל אותם בכך שאתם יכולים להצפין קוד פרודקשן, או להצפין / לג'ברש את הקוד שקורא למפתח עצמו ושלל טריקים נוספים שבא לכם, כך שגם אם פורץ יעתיק את ה-DB, הוא לא יוכל לעשות איתו כלום (חוץ מאשר אולי לראות דברים שהוא לא היה אמור לראות מבחינת תוכן).
כל עניין הצפנת סיסמאות, שמות משתמשים וכתובות מייל אינו מורכב כל כך ליישום. הכל תלוי באיזה DB ובאיזו שפה אתם מתכנתים, לפיכך מומלץ להקדיש לכך כמה שעות פעם אחתוליישם הצפנה רצינית בקוד ובמפתחות כדי שאם לכם יפרצו, לא תצטרכו לעמוד מול כל העולם ואחותו עם פדיחה רצינית וצורך לענות לעיתונאים איך אתם כל כך חסרי אחריות. במקרה של תפוז, לדוגמא, המזל הגדול של תפוז זה שרוב המשתמשים הם עם שמות משתמשים בעברית והפורץ לא ידע בכלל מה זה UTF-8, אז אי אפשר להשתמש ברשימות שהופצו כדי להיכנס למערכת של תפוז (אבל אפשר להספים את המשתמשים…)