Menu
CoddyTech

בדיקת סיסמה

חלק מהיחידה אימות ואבטחה במסלול ה-Node.js של Coddy. שיעור 2 מתוך 17.

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

משווים באמצעות timingSafeEqual, ולא באמצעות ===. === נעצר בבייט הראשון ששונה, ולכן תוקף שמודד את משך הזמן של תשובות רבות יכול ללמוד איזה חלק מהניחוש שלו היה נכון. timingSafeEqual נמשך תמיד אותו פרק זמן. הוא משווה בין שני Buffer-ים באותו אורך וזורק שגיאה כאשר אורכיהם שונים.

import { timingSafeEqual } from 'node:crypto';

const expected = Buffer.from(process.env.API_KEY);
const given = Buffer.from(req.get('x-api-key') ?? '');
const ok = given.length === expected.length && timingSafeEqual(given, expected);

Buffer.from(hex, 'hex') ממיר טקסט הקסדצימלי בחזרה לבתים.

challenge icon

אתגר

קל
  • בקובץ passwords.js, הוסיפו וייצאו את verifyPassword(password, stored): אמת כשהסיסמה היא זו שיצרה את הערך השמור.
  • בקובץ server.js, הוסיפו את POST /login עם { username, password }: החזירו 200 עם { username }, או 401 עם { "error": "Wrong username or password" } במקרה של סיסמה שגויה או שם משתמש לא מוכר.

הירשמו בשם ada, התחברו, ואז התחברו עם סיסמה שגויה.

נסו בעצמכם

import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';

const scryptAsync = promisify(scrypt);

// ממירה סיסמה לטקסט ש־signup שומר.
export async function hashPassword(password) {
    const salt = randomBytes(16).toString('hex');
    const key = await scryptAsync(password, salt, 64);
    return `${salt}:${key.toString('hex')}`;
}

כל השיעורים ביחידה אימות ואבטחה