מלח הארץ

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

כאשר שומרים פרטים של משתמש וסיסמה, חשוב לא לשמור את הסיסמה עצמה, אלא חתימה חד חד ערכית שלה.
הסיבה לכך מאוד פשוטה: אם בטעות מישהו מצליח לגשת למסד הנתונים, הוא לא ידע מה הסיסמה של המשתמשים שלך, ובכך לפחות עמודת הסיסמאות אינה שימושית בצורה ה"רגילה" שלה.
בשביל שהיא כן תהיה שימושית, צריך בעצם ליצור סוג של מילון שמתרגם hash למה שהרכיב אותו.

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

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

כאשר "חותמים", כיום מומלץ בחום לא לעבוד יותר עם md5, היות ויש לו התנגשויות. כלומר ישנה יותר מסדרת בתים אחת שיכולה להיות עם אותה חתימה. אז אני משתמש ב sha256 במקום. הנה קוד רובי המדגים כיצד יש לבצע זאת:

require 'digest/sha2'
def to_hash(str)
  (Digest::SHA256.new << str).to_s
end

puts to_hash('')
# e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

כך בעצם נראת חתימה. כאן אני מדגים חתימה של מחרוזת ריקה. כי גם לה יש ערך.
בשביל לחתום סיסמה עם Salt, ניתן לעשות זאת בצורה הבאה:

require 'securerandom'
require 'digest/sha2'

def to_hash(str)
  (Digest::SHA256.new << str).to_s
end

# random enough for you ?
salt = SecureRandom.uuid + ' ' + SecureRandom.base64(64)
password = 'secretpassword'

hashed_password = to_hash(salt + password)
# c4eaec9cc489bee913c1ad82c35363c4a0c64549a54b188d293e4e496363d69d
# for example

במסד הנתונים שומרים בשדה של הסיסמה את התוכן הקיים ב hashed_password.
בנוסף צריכה להיות עמודה עבור salt ומן הסתם שומרים את התוכן הקיים במשתנה salt.
החיפוש הוא על שם משתמש (שחייב להיות ייחודי), ואז בודקים זאת ככה:

... # found the user etc...
salt = user.salt
password = params[:password]
if to_hash(salt + password) == user.password
  puts 'yes'
else
  puts 'Invalid user name or password'
end

וככה עובדים עם Salt וסיסמאות.
ניתן למצוא מימוש של אלגוריתמי sha עבור פסקל, בdcpcrypt.
הדגמה לשימוש בו.

5 מחשבות על “מלח הארץ

    1. ירדן

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

  1. פינגבק: הסכנות בשימוש md5 כסיסמה | לראות שונה

  2. פינגבק: NaCl, Sodium והצפנה | לראות שונה

כתיבת תגובה

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

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s