การยืนยันตัวตน (Authentication) เปรียบเสมือนพนักงานรักษาความปลอดภัยที่คอยคัดกรองคนเข้าประตูแอปพลิเคชันของคุณ ทุกครั้งที่มีคนลงทะเบียนหรือเข้าสู่ระบบ ระบบของคุณต้องตัดสินใจว่าพวกเขาคือคนที่พวกเขาอ้างว่าเป็นจริงหรือไม่ หากคุณตัดสินใจผิดพลาด มันไม่ใช่แค่การแก้บั๊กเรื่องการล็อกอินล้มเหลวเท่านั้น แต่คุณกำลังเสี่ยงที่จะทำให้ข้อมูลจริงของผู้ใช้หลุดออกไปจากระบบ การทำสิ่งนี้อย่างถูกต้องจำเป็นต้องมีเครื่องมือที่เชื่อถือได้สองอย่าง: Bcrypt สำหรับการปกป้องรหัสผ่านในขณะที่จัดเก็บ (at rest) และ JSON Web Tokens สำหรับการตรวจสอบตัวตนในขณะที่ผู้ใช้งานเคลื่อนที่ไปมาในแอปของคุณ

ทำไมการจัดเก็บแบบ Plaintext ถึงเป็นอันตราย

หากคุณจะจดจำกฎเพียงข้อเดียวจากบทความนี้ ขอให้เป็นข้อนี้: อย่าเก็บรหัสผ่านเป็นข้อความธรรมดา (plaintext) ในฐานข้อมูลของคุณ ไม่สำคัญว่าฐานข้อมูลของคุณจะอยู่หลังไฟร์วอลล์หรือคุณจะเชื่อใจวิศวกรทุกคนในทีมมากแค่ไหน การเขียนรหัสผ่านลงในตารางในรูปแบบดิบ (raw form) ก็เหมือนกับการวางกุญแจบ้านไว้ใต้พรมเช็ดเท้า ทันทีที่มีใครเข้าถึงฐานข้อมูลนั้นได้—ไม่ว่าจะผ่าน API ที่ตั้งค่าผิดพลาด, ไฟล์สำรองข้อมูลที่รั่วไหล หรือการโจมตีแบบ injection—ข้อมูลประจำตัวทุกอย่างจะถูกเปิดเผยในทันที

ความเสียหายจะทวีคูณเพราะผู้คนมักใช้รหัสผ่านซ้ำกัน การรั่วไหลเพียงครั้งเดียวอาจไม่เพียงแต่กระทบต่อแอปพลิเคชันของคุณเท่านั้น แต่ยังรวมถึงอีเมล, บัญชีธนาคาร และโซเชียลมีเดียของผู้ใช้ด้วย นี่คือเหตุผลที่เราต้องทำ hashing รหัสผ่าน การทำ hashing จะเปลี่ยนรหัสผ่านให้กลายเป็นสตริงที่ถูกสลับตำแหน่งจนไม่เหลือเค้าเดิม กระบวนการนี้เป็นการทำงานแบบทางเดียวและไม่สามารถย้อนกลับได้ คุณไม่สามารถเท "กรดทางคณิตศาสตร์" ลงบน hash เพื่อละลายมันกลับไปเป็นรหัสผ่านเดิมที่สร้างมันขึ้นมาได้

การทำ Hashing รหัสผ่านด้วย Bcrypt

Bcrypt คือฟังก์ชันการทำ hashing ที่ถูกสร้างขึ้นมาเพื่อรหัสผ่านโดยเฉพาะ มันจะนำสตริงธรรมดามาผ่านกระบวนการ Blowfish cipher และส่งผลลัพธ์กลับมาในรูปแบบที่คล้ายกับ $2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy ส่วนนำหน้า (prefix) นั้นจะบอกคุณถึงอัลกอริทึมและค่า cost factor ส่วนหางที่ยาวคือการผสมกันระหว่าง salt และตัว hash เอง

Salt คือข้อมูลสุ่มที่ถูกผสมเข้าไปในรหัสผ่านก่อนที่จะเริ่มการทำ hashing เนื่องจาก salt จะมีความเฉพาะตัวสำหรับผู้ใช้แต่ละคน ดังนั้นคนสองคนที่เลือกใช้รหัสผ่าน "password123" เหมือนกัน จะได้ค่า hash ที่แตกต่างกันอย่างสิ้นเชิงในฐานข้อมูลของคุณ ความแตกต่างเพียงเล็กน้อยนี้จะช่วยป้องกัน rainbow tables—ซึ่งเป็นพจนานุกรมของค่า hash สำหรับรหัสผ่านทั่วไปที่ถูกคำนวณไว้ล่วงหน้า—เพราะผู้โจมตีจะต้องสร้างตารางใหม่ทั้งหมดสำหรับ salt ที่ไม่ซ้ำกันในแต่ละครั้ง

Bcrypt ยังถูกออกแบบมาให้ทำงานช้าอย่างตั้งใจ ฮาร์ดแวร์สมัยใหม่สามารถเดาค่า hash ได้หลายพันล้านค่าต่อวินาทีด้วยอัลกอริทึมที่รวดเร็วอย่าง SHA-256 แต่ Bcrypt จะค่อยๆ ทำงาน มันจะรันกระบวนการ hashing ซ้ำหลายครั้ง โดยควบคุมด้วยค่า cost factor ที่คุณสามารถเพิ่มขึ้นได้เมื่อคอมพิวเตอร์มีความเร็วมากขึ้น ความล่าช้านี้จะลงโทษใครก็ตามที่พยายามใช้วิธี brute-force เพื่อเจาะฐานข้อมูลที่ถูกขโมยไป ผู้ใช้งานทั่วไปที่ต้องรอเพิ่มขึ้นเพียงสองร้อยมิลลิวินาทีระหว่างการล็อกอินจะไม่รู้สึกถึงความแตกต่าง แต่ผู้โจมตีที่พยายามทดสอบการเดาเป็นล้านๆ ครั้งจะรู้สึกได้อย่างแน่นอน

การทำงานของ JSON Web Tokens

ในขณะที่ Bcrypt ดูแลประตูหน้า JWT จะทำหน้าที่เหมือนบัตรผ่านทางเดิน JSON Web Token คือสตริงที่กะทัดรัดและปลอดภัยสำหรับ URL (URL-safe) ซึ่งพิสูจน์ว่าผู้ใช้ได้รับการยืนยันตัวตนเรียบร้อยแล้ว ให้คิดซะว่ามันคือบัตรประจำตัวดิจิทัลที่เซิร์ฟเวอร์ออกให้และไคลเอนต์พกติดตัวไปมา

JWT ประกอบด้วยสามส่วนที่คั่นด้วยจุด ได้แก่ header, payload และ signature โดยที่ header จะระบุประเภทของ token และอัลกอริทึมที่ใช้ในการลงลายมือชื่อ ส่วน payload จะบรรจุ claims—ซึ่งเป็นข้อความยืนยันเกี่ยวกับผู้ใช้และตัว token เอง—เช่น user ID, username และเวลาหมดอายุ (expiration timestamp) ส่วน signature คือตราประทับทางวิทยาการรหัสลับ (cryptographic seal) เซิร์ฟเวอร์สร้างมันขึ้นมาโดยการเข้ารหัส header และ payload จากนั้นจึงนำไปผ่าน secret key หากมีใครพยายามแก้ไข payload ลายเซ็นจะไม่ตรงกันอีกต่อไป และเซิร์ฟเวอร์จะปฏิเสธ token นั้นทันที