- Hashing הוא תהליך חד-כיווני (One-way) שהופך סיסמה לערך לא פענוח — בניגוד להצפנה שניתנת לשחזור.
- bcrypt מוסיף Salt רנדומלי לכל סיסמה ומבצע 1,024 פעמי hash — מה שהופך פריצה למאוד קשה.
- cost factor ב-bcrypt קובע כמה פעמים מתבצע ה-Hashing (2^10 = 1,024 בברירת מחדל) — ניתן להגדיל לפי הצורך.
- אימות סיסמה bcrypt שומר את ה-Salt בתוך ה-Hash, ומשתמש בו להשוואה בזמן Login ללא צורך בפענוח.
האם אי פעם חשבתם איך הסיסמאות שלנו נשמרות ב-Database? האם הם נשמרות כאל טקסט רגיל וקריא או שהן נשמרות בדרך מאובטחת יותר? ומה הסכנות בשמירת סיסמאות כאל טקסט רגיל וקריא? במאמר הזה אנחנו נדבר על אחד מהנושאים החשובים ביותר בתחום הסייבר והאבטחה: אבטחת סיסמאות. המטרה שלנו היא להבין מושגים בסייסים בעולם אבטחת סיסמאות ואת התהליך של שמירת הסיסמאות ב-Database. בואו נתחיל.
שמירת סיסמאות במבט כללי
שמירת סיסמאות כטקסט רגיל (plaintext) במסד נתונים היא אחת הפגיעויות החמורות ביותר שאפשר לגרום. אם תוקף פורץ ל-Database, הוא מקבל גישה מיידית לכל הסיסמאות. הפתרון הנכון הוא Hashing — תהליך חד-כיווני שהופך סיסמה לערך לא-פענוח. ספריית bcrypt מוסיפה Salt רנדומלי ומבצעת 1,024 פעמי hash, מה שהופך פריצה למחשב ביתי לתהליך של כ-193 שנים לסיסמה של 8 תווים.
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, שהוא ערך רנדומלי לחלוטין שמתווסף לסיסמה שלכם והופך אותה לארוכה יותר וקשה יותר לפיצוח. כמה ארוכה יותר? כמו משהו כזה:
$2a$10$vI8aWBnW3fID.ZQ4/zo1G.ObJm/C4/NoeP1sUQ0wUxTWsFGMv.ZW.
הסימן $ שאתם רואים, הוא מפריד בין מידע למידע. כלומר אנחנו מבינים שהערך הגדול הזה מחולק ל-4 חלקים שכל אחד מהם מייצג מיידע מסויים. אז בואו נדמה את התהליך של ה-Authentication ואיך אנחנו שומרים את הסיסמא שלנו ב-Database בצורה מאובטח ותקינה בעזרת bcrypt:
תהליך שמירה ואבטחת הסיסמא
אז בואו נדמה את התהליך של ה-Authentication ואיך אנחנו שומרים את הסיסמא שלנו ב-Database בצורה מאובטח ותקינה בעזרת bcrypt:
הסיסמא של המשתמש היא 123
bcrypt מייצר salt, כלומר ערך רנדומלי לחלוטין בכל פעם, (אפילו אם הסיסמאות שוות), לדוגמה - vI8aWBnW3fID.ZQ4/zo1G.
bcrypt לא מדביק פשוט את הסיסמה 123 ל-salt vI8aWBnW3fID.ZQ4/zo1G. במקום זה, הוא משלב אותם בצורה חכמה ובטוחה בתוך אלגוריתם מיוחד שמייצר את ה-Hash.
bcrypt משתמש באלגוריתם פנימי שמערבב את הסיסמה 123 עם ה-salt vI8aWBnW3fID.ZQ4/zo1G בצורה בטוחה, ויוצר את ערך ה-Hash, לדוגמה: ObJm/C4/NoeP1sUQ0wUxTWsFGMv.ZW
התוצאה הסופית שאותה אנחנו שומרים ב-Database שלנו היא:
$2a$10$vI8aWBnW3fID.ZQ4/zo1G.ObJm/C4/NoeP1sUQ0wUxTWsFGMv.ZW
הסימן 2a הוא האלגוריתם שאיתו bcrypt השתמשה, והסימן 10 הוא ה-cost factor, כלומר מספר הפעמים שביצענו Hash. במקרה הזה אנחנו מדברים על תהליך שבו ה-Hashing מתבצע 1024 פעמים - כלומר 2^10 פעמים. בכל פעם, ה-Hash שנוצר בשלב הקודם מהווה את הקלט ל-Hashing הבא. תהליך זה מעלה את רמת האבטחה של הסיסמאות שלנו באופן משמעותי, מכיוון שכל שלב מוסיף סיבוכיות ומחייב מאמץ חישובי נוסף.
אימות הסיסמא
אז איך המשתמש מצליח להיכנס למערכת אם הסיסמה שלו היא בכלל123, אבל מה ששמור ב-Database נראה שונה לגמרי? bcrypt שומרת בתוך מחרוזת ה-Hash גם את המידע שצריך כדי לבדוק את הסיסמה – כולל ה-salt וה-cost – כשהכול מופרד באמצעות הסימן $. כאשר המשתמש מנסה להתחבר, bcrypt לוקחת את הסיסמה שהוזנה, מפעילה עליה את אותו תהליך Hashing עם אותם נתונים, ומשווה את התוצאה לערך שב-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 שנים! כדי לנסות לפצח את הסיסמה שלכם.
שאלות נפוצות על שמירת סיסמאות
מה ההבדל בין Hashing ל-Encryption?
Hashing הוא תהליך חד-כיווני (One-way) — ממיר סיסמה לערך hash שלא ניתן לשחזר לסיסמה המקורית. Encryption הוא דו-כיווני (Two-way) — ניתן להצפין ולפענח בחזרה לערך המקורי. לאבטחת סיסמאות, Hashing הוא הנכון, כי אף אחד — כולל מפתחי המערכת — לא צריך לדעת מה הסיסמה המקורית.
מה זה Salt ב-bcrypt?
Salt הוא ערך רנדומלי לחלוטין שמתווסף לסיסמה לפני ה-Hashing. ב-bcrypt נוצר Salt חדש בכל פעם — אפילו אם שני משתמשים בחרו אותה סיסמה, ה-hash שלהם יהיה שונה לגמרי. ה-Salt נשמר בתוך ה-hash עצמו (מופרד על ידי $) ומשמש לאימות הסיסמה בזמן כניסה — ללא צורך בשמירה נפרדת שלו.
מה זה cost factor ב-bcrypt?
Cost factor קובע כמה פעמים יבוצע ה-Hashing. Cost factor של 10 פירושו 2^10 = 1,024 פעמי hash. ככל שהמספר גבוה יותר, כך ה-hash איטי יותר לחישוב — מה שמקשה על תוקפים לנסות מיליוני ניחושים בשנייה. ניתן להגדיל את ה-cost factor עם הזמן כדי להתמודד עם מחשבים חזקים יותר בלי לשנות קוד.
איך bcrypt מאמת סיסמה בזמן Login?
כשמשתמש מנסה להתחבר, bcrypt לוקחת את הסיסמה שהוזנה ואת ה-hash השמור (שמכיל את ה-Salt). היא מפעילה את אותו אלגוריתם עם אותו Salt על הסיסמה החדשה, ומשווה את התוצאה ל-hash הקיים. אם הם תואמים — הסיסמה נכונה. כך לעולם לא צריך לפענח את הסיסמה המקורית ולא קיים סיכון דליפה.
כמה זמן לוקח לפרוץ סיסמה ב-brute force?
סיסמה של 8 תווים מאותיות, ספרות ותווים מיוחדים (94 תווים אפשריים) יוצרת 94^8 קרוב ל-6 קוודריליון קומבינציות. מחשב ביתי שמבצע מיליון ניחושים בשנייה יצטרך כ-193 שנים לנסות את כולן. bcrypt מאט את החישוב עוד יותר כי כל ניחוש דורש 1,024 פעמי hash — מה שהופך brute force לבלתי-מעשי בפועל.
