לעולם אל תשמרו סיסמאות
חלק מהיחידה אימות ואבטחה במסלול ה-Node.js של Coddy. שיעור 4 מתוך 24.
אנשים משתמשים שוב בסיסמאות, ולכן סיסמה גלויה שדלפה עלולה לחשוף חשבונות במקומות אחרים. שמור גיבוב סיסמה עם מלח: ערך נגזר שמאמתים באמצעות חישוב מחדש שלו, במקום לפענח אותו.
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(inviteCode, salt, 32);
const saved = salt + '.' + key.toString('hex');הדוגמה הזאת משלבת מלח ומפתח נגזר עבור קוד הזמנה. המפריד מאפשר לאימות לשחזר את המלח ולגזור מפתח נוסף עם אותם הפרמטרים. במשימת הסיסמה שלך נעשה שימוש במפריד ובאורך מפתח משלה. צור את המלח עבור כל סיסמה חדשה, גזור את המפתח ואז שמור את שניהם. גם גיבובים עם מלח דורשים סיסמאות חזקות, כי תוקף יכול לנסות ניחושים.
אתגר
קלכרגע ההרשמה שומרת כל סיסמה בדיוק כפי שהוקלדה. יש לשנות זאת כך שתשמור במקום זאת גיבוב עם מלח, כדי שמסד נתונים שדלף לא יחשוף את הסיסמאות.
- בקובץ
passwords.js, יש לשנות אתhashPassword(password)כך שתחזיר את הטקסט שההרשמה שומרת, בפורמט מלח, נקודתיים, גיבוב:- המלח הוא 16 בתים אקראיים, שנוצרים מחדש בכל קריאה ונכתבים בהקסדצימלי: 32 תווים מתוך 0 עד 9 ו־a עד f.
- הגיבוב הוא מפתח באורך 64 בתים ש־
scryptיוצרת מהסיסמה ומהמלח הזה, וגם הוא נכתב בהקסדצימלי: 128 תווים. הארגומנט השלישי שלscryptAsyncהוא אורך המפתח בבתים. - יש לחבר את השניים באמצעות נקודתיים. ערך שמור נראה כך:
f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
- אין צורך לשנות את
server.js. הפעולהPOST /signupשבו כבר קוראת ל־hashPasswordושומרת את הערך שהיא מחזירה. יש בו גם אתGET /debug/users/:username, שמציגה מה נשמר עבור משתמש אחד. הנתיב הזה קיים רק כדי שתוכלו לבדוק; באפליקציה אמיתית הוא לעולם לא קיים.
נסו זאת: לחצו על "שחק". שלחו POST /signup עם {"username": "ada", "password": "correct horse"}. תקבלו סטטוס 201 ואת {"username": "ada"}. שלחו את אותו גוף עם "username": "bob". כעת שלחו GET /debug/users/ada, ואז GET /debug/users/bob. כל passwordHash מכיל 32 תווים, נקודתיים ועוד 128 תווים. שני הערכים שונים, אף על פי ש־ada ו־bob בחרו באותה סיסמה.
נסו בעצמכם
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// ממירה סיסמה לטקסט ש-signup שומר.
// לעת עתה היא משאירה את הסיסמה כפי שהוקלדה.
export async function hashPassword(password) {
return password;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה אימות ואבטחה
1סיסמאות
בתים וטקסט הקסדצימליגזירת מפתח מסיסמהSalt חדשלעולם אל תשמרו סיסמאותהשוואת בתי המפתחבדיקת סיסמהכללי הרשמהתרגלו בעצמכם: Express אונליין