האם אי פעם חשבתם איך הסיסמאות שלנו נשמרות ב-Database? האם הם נשמרות כאל טקסט רגיל וקריא או שהן נשמרות בדרך מאובטחת יותר? ומה הסכנות בשמירת סיסמאות כאל טקסט רגיל וקריא? במאמר הזה אנחנו נדבר על אחד מהנושאים החשובים ביותר בתחום הסייבר והאבטחה: אבטחת סיסמאות. המטרה שלנו היא להבין מושגים בסייסים בעולם אבטחת סיסמאות ואת התהליך של שמירת הסיסמאות ב-Database. בואו נתחיל.
Hashing & Hash
תהליך Hashing מעניק לנו את היכולת להמיר ערך מסויים שהוא קריא לאדם כמו סיסמא "123" לסדרה של תווים שנראית כאילו היא נבחרה באופן אקראי, לדגומה "nf87%KFDJ@". הערך "הרנדומלי" הזה נקרא Hash. התהליך שה-Hashing מבצע הוא One-way, כלומר לא ניתן להחזיר ה-hash למצבו המקורי "123". וזה בדיוק מה שאנחנו רוצים. כלומר אנחנו לא רוצים לאפשר לערך הרנדומלי הזה לבצע שיחזור לערך המקורי, לכן זה נקרא One-way.
Encryption & Decryption
מאפשרים לנו לחזור לערך המקורי, כלומר להפוך ערך קריא כמו סיסמא "123" לערך מוצפן, לדגומה "nf87%KFDJ@", אבל שניתן להחזיר אותו בחזרה לערך המקורי "123". הדבר הזה נקרא Two-way, כלומר אפשר להצפין וגם לפענח, וזו יכולה להיות בעיה, כי אנחנו לא רוצים שתהייה את האופציה של פענוח.
האם Hashing ו-Encryption טובות לאבטחת סיסמאות?
אז איך אנחנו צריכים לשמור סיסמאות ב-Database שלנו? אתם חושבים שזה יהיה רעיון טוב אם נשתמש ב-Hashing או ב-Encryption? אז זה רעיון גרוע! וזה מכמה סיבות:
אם נשתמש ב-Hashing, הסיסמא שלנו תישמר כאל Hash, כלומר סיסמא של "123", תהפוך ל-"nf87%KFDJ@", ולכן אם אקר הצליח לפרוץ לנו ל-Database הוא לא יראה את הסיסמאות שלכם, אלא רק את הערך ה-Hash של הסיסמאות שלכם. אבל מי אמר שאקרים לא יכולים בעצמם לקחת ערכים נפוצים כמו סיסמאות של "123" ולראות את ערך ה-Hash שלהם. במילים אחרות האקרים יכולים לקחת סיסמאות נפוצות לבצע עליהם Hashing, ואז לבדוק את ההתאמה שלהם ב-Database שלנו, ואז כמובן לגלות את הסיסמא.
סיבה שנייה היא, שתהליך ה-Hashing נותן לנו כל פעם את אותו ה-Hash, כלומר אם נבצע Hashing על הסיסמא "123", תמיד אנחנו נקבל את אותו ערך של ה-Hash של "123", לכן זה גם לא טוב, אנחנו צריכים משהו שמשתנה תמיד ולא צפוי וככה נוכל להקשות על גילוי הסיסמא שלנו במערכת.
אם נשתמש ב-Encryption & Decryption זה יהיה גרוע, כי הם מיישמים Two-way, מה שאומר שאנחנו יכולים להצפין ערך אבל גם לשחזר את אותו ערך למצב המקורי שלו. ולכן גם האופציה הזו לא טובה.
שימוש בספריית bcrypt
ספריית bcrypt מציעה שיטה חזקה ל-Hashing של סיסמאות. היא לא רק עושה את התהליך של ה-Hashing, אלא היא גם יוצרת בנוסף משהו שנקרא Salt, שהוא ערך רנדומלי לחלוטין שמתווסף לסיסמה שלכם והופך אותה לארוכה יותר וקשה יותר לפיצוח. כמה ארוכה יותר? כמו משהו כזה:
הסימן $ שאתם רואים, הוא מפריד בין מידע למידע. כלומר אנחנו מבינים שהערך הגדול הזה מחולק ל-4 חלקים שכל אחד מהם מייצג מיידע מסויים. אז בואו נדמה את התהליך של ה-Authentication ואיך אנחנו שומרים את הסיסמא שלנו ב-Database בצורה מאובטח ותקינה בעזרת bcrypt:
תהליך שמירה ואבטחת הסיסמא
אז בואו נדמה את התהליך של ה-Authentication ואיך אנחנו שומרים את הסיסמא שלנו ב-Database בצורה מאובטח ותקינה בעזרת bcrypt:
הסיסמא של המשתמש היא 123
bcrypt מייצר salt, כלומר ערך רנדומלי לחלוטין בכל פעם, (אפילו אם הסיסמאות שוות), לדוגמה - vI8aWBnW3fID.ZQ4/zo1G.
הסיסמא של המשתמש 123 מצורפת ל-salt, כלומר - vI8aWBnW3fID.ZQ4/zo1G123.
bcrypt מבצעת Hashing על כל הערך הזה vI8aWBnW3fID.ZQ4/zo1G123, והתוצאה היא: ObJm/C4/NoeP1sUQ0wUxTWsFGMv.ZW
התוצאה הסופית שאותה אנחנו שומרים ב-Database שלנו היא:
הסימן 2a הוא האלגוריתם שאיתו bcrypt השתמשה, והסימן 10 הוא ה-cost factor, כלומר מספר הפעמים שביצענו Hash. במקרה הזה אנחנו מדברים על תהליך שבו ה-Hashing מתבצע 1024 פעמים - כלומר 2^10 פעמים. בכל פעם, ה-Hash שנוצר בשלב הקודם מהווה את הקלט ל-Hashing הבא. תהליך זה מעלה את רמת האבטחה של הסיסמאות שלנו באופן משמעותי, מכיוון שכל שלב מוסיף סיבוכיות ומחייב מאמץ חישובי נוסף.
אימות הסיסמא
אז איך המשתמש עדיין מצליח להיכנס למערכת אם הסיסמא שלו היא בכלל 123, אבל הסיסמא שאנחנו שומרים ב-Database היא שונה לחלוטין? זוכרים שאמרנו ש-bcrypt יודעת לחלק את הערך הגדול הזה שאנחנו מקבלים ל-4 חלקים שמופרדים על ידי הסימן $? בעצם מה שקורה זה ש-bcrypt מבצעת כל פעם את אותו התהליך שעכשיו עשינו, והיא משווה את התוצאה שהיא קיבלה לתוצאה שיש לנו ב-Database. אם התוצאה שלה היא כמו התוצאה שלנו ב-Database, הסיסמא נכונה והמשתמש יכול להיכנס למערכת שלנו.
ניתוח אופציות לפריצת סיסמה
כדי להבין את האתגר של פריצת סיסמה, בואו נבחן סיסמה בת 8 תווים המורכבת מאותיות אנגליות (גדולות וקטנות), מספרים, ותווים מיוחדים:
אותיות גדולות: 26
אותיות קטנות: 26
ספרות (0-9): 10
תווים מיוחדים: 32
סה"כ תווים אפשריים: 94
מספר הקומבינציות האפשריות לסיסמה באורך 8 תווים הוא 948, שזה במילים פשוטות 6,095,689,385,410,816. אם נניח שמחשב מתקדם (שאין בבתים רגילים) יכול לבצע מיליארד (109) ניחושים בשנייה, הזמן הדרוש לפריצה יהיה כ-6,095,689 שניות, שזה שקול לכ-0.193 שנים או כ-70 ימים. אבל נניח שאין ברשותנו מחשב מתקדם, אלא מחשב סטנדרטי שיש בבתים, ונניח שמספר הפעולות שהוא יכול לבצע מצומצמות יותר (106), זה אומר שייקח למחשב בערך 193 שנים! כדי לנסות לפצח את הסיסמה שלכם.