User enumeration là việc kẻ tấn công xác định được email/username nào tồn tại trong hệ thống. Có danh sách account thật thì credential stuffing và phishing hiệu quả hơn nhiều.
Ba kênh rò rỉ hay gặp:
1. Nội dung thông báo khác nhau — "Email không tồn tại" vs "Mật khẩu sai". Phải trả về một thông báo duy nhất: "Email hoặc mật khẩu không đúng".
2. Mã trạng thái / cấu trúc response khác nhau — 404 cho email lạ nhưng 401 cho sai mật khẩu; hoặc chỉ khác nhau độ dài body. Phải đồng nhất status, body, header.
3. Thời gian phản hồi khác nhau — đây là chỗ hay bị bỏ sót. Nếu email không tồn tại thì code return sớm mà không chạy bcrypt, còn email tồn tại thì chạy bcrypt mất ~100ms → chênh lệch thời gian đủ để phân biệt.
// Wrong: returns early, no hash comparison → measurably faster
const user = await findByEmail(email)
if (!user) return fail()
const ok = await bcrypt.compare(password, user.hash)
// Better: always spend the same work
const user = await findByEmail(email)
const hash = user?.hash ?? DUMMY_HASH // precomputed hash of a random string
const ok = await bcrypt.compare(password, hash)
if (!user || !ok) return fail()Các luồng khác cũng rò rỉ tương tự và thường bị quên: đăng ký ("email đã được dùng"), quên mật khẩu, và cả giới hạn tần suất nếu chỉ áp cho account có thật.