Bun.password: Hash รหัสผ่านด้วย Argon2id โดยไม่ต่อ String เอง
ฐานข้อมูลรหัสผ่านไม่ควรเก็บข้อความเดิมและไม่ควรใช้ hash เร็วอย่าง SHA-256 ครับ ผู้โจมตีที่ขโมยตารางไปจะลองเดารหัสผ่านได้มหาศาลต่อวินาที เราต้องใช้ password hashing ที่ตั้งใจให้กินเวลาและหน่วยความจำ เหมือนประตูที่เจ้าของเปิดได้ช้าลงนิดเดียว แต่ทำให้คนลองกุญแจล้านดอกจ่ายแพงมาก
Bun.password ให้ hash และ verify ใน runtime โดยค่าเริ่มต้นใช้ Argon2id สร้าง salt แบบสุ่มและรวมพารามิเตอร์ไว้ในผลลัพธ์ การ verify จึงอ่าน algorithm จาก hash ได้ ไม่ต้องต่อ PHC string ด้วยมือ
WHY: Cost ต้องแพงสำหรับผู้โจมตี แต่รับไหวสำหรับระบบ
การเลือกรอบสูงสุดไม่ใช่คำตอบ เพราะ login burst อาจกิน CPU และ memory จนกลายเป็น denial of service ให้ benchmark บน instance ขนาดเล็กสุดที่ใช้งานจริง กำหนด latency budget และ concurrency cap จากนั้นค่อยเลือก timeCost กับ memoryCost ตาม threat model
ตัวอย่างนี้ใช้ค่าต่ำเพื่อให้ smoke test รันเร็ว ไม่ใช่ค่าที่แนะนำสำหรับ production ส่วน production ควรอ้าง baseline ล่าสุดของ OWASP แล้ววัดกับฮาร์ดแวร์จริง
const password = "correct horse battery staple";
const digest = await Bun.password.hash(password, {
algorithm: "argon2id",
memoryCost: 4096,
timeCost: 1,
});
if (digest.includes(password)) {
throw new Error("digest leaked the original password");
}
if (!(await Bun.password.verify(password, digest))) {
throw new Error("correct password was rejected");
}
if (await Bun.password.verify("wrong password", digest)) {
throw new Error("wrong password was accepted");
}
console.log("password hashing smoke test passed");
HOW: ออกแบบเส้นทางสมัครและย้ายระบบ
จำกัดขนาด request ก่อนเข้าฟังก์ชัน hash เพื่อกัน payload ใหญ่ผิดปกติ แต่บอกผู้ใช้เป็นนโยบายที่เป็นธรรม อย่าตัดรหัสผ่านเงียบ ๆ เก็บ digest ทั้งก้อนและไม่แยก salt ออกโดยไม่มีเหตุผล เพราะรูปแบบ self-describing ช่วยให้ย้าย cost ในอนาคตได้
เมื่อ login สำเร็จ ให้ตรวจว่าพารามิเตอร์เก่ากว่า policy หรือไม่ ถ้าเก่าให้ rehash รหัสผ่านที่เพิ่ง verify ผ่านแล้วและอัปเดตแบบ atomic วิธีนี้ทยอยย้ายโดยไม่ต้องรู้ plaintext ล่วงหน้า สำหรับบัญชีที่ไม่กลับมา login อาจใช้ reset campaign แทน
ใช้ async API บน server request path เพราะ sync variant จะ block thread จัด rate limit ตามบัญชีและ IP แบบไม่เปิดช่อง enumerate user และอย่า log password หรือ digest เต็ม เก็บ secret pepper แยกจากฐานข้อมูลเฉพาะเมื่อทีมมีระบบหมุนและสำรอง key ที่พร้อม
Recap
- ใช้ Argon2id ไม่ใช้ hash เร็วทั่วไป
- benchmark cost บนเครื่อง production ที่เล็กสุด
- จำกัดขนาดอินพุตและ login concurrency
- rehash หลัง verify สำเร็จเมื่อ policy เปลี่ยน
- ไม่ log plaintext หรือ digest เต็ม
เริ่มด้วย benchmark 50–100 ครั้งใน staging แล้วตั้ง budget จาก p95 ก่อนเลือกค่า production ครับ