← Blog

กุญแจเข้ารหัสของแต่ละลูกค้า — บทเรียนจากตอนที่หมุนกุญแจแล้วล้มกลางทาง

ระบบที่ดูแลฐานข้อมูลของลูกค้าหลายรายต้องเก็บรหัสผ่านสำหรับเชื่อมต่อฐานข้อมูลของแต่ละรายไว้ที่ไหนสักแห่ง

บทความนี้เล่าว่าเราเก็บมันอย่างไร ทำไมถึงเปลี่ยนวิธีกลางทาง และสองเหตุการณ์ที่สอนเรามากที่สุด

จุดเริ่มต้น — กุญแจเดียวทั้งระบบ

ตอนแรกเราเข้ารหัสรหัสผ่านฐานข้อมูลด้วยกุญแจดอกเดียวที่ใช้กับทุกลูกค้า ซึ่งดีกว่าเก็บเป็นข้อความธรรมดาอย่างเห็นได้ชัด และเป็นจุดเริ่มต้นที่สมเหตุสมผล

แต่พอมองต่ออีกขั้นจะเห็นปัญหา — ถ้ากุญแจดอกนั้นรั่ว ลูกค้าทุกรายอยู่ในความเสี่ยงพร้อมกัน และบริการของลูกค้ารายหนึ่งที่รันอยู่บนเครื่องเดียวกันก็ถอดรหัสของอีกรายได้ ทั้งที่ไม่ควรมีเหตุผลอะไรให้ทำได้

การเข้ารหัสที่ไม่มีการแยกขอบเขตจึงป้องกันได้แค่กรณีที่ฐานข้อมูลรั่วโดยไม่มีอย่างอื่นรั่วตามเท่านั้น ซึ่งเป็นสมมติฐานที่มองโลกในแง่ดีเกินไป

เปลี่ยนเป็นกุญแจแยกต่อโดเมน

เราเปลี่ยนให้แต่ละโดเมนมีกุญแจของตัวเอง โดยบริการของแต่ละโดเมนเห็นเฉพาะกุญแจของตัวเองเท่านั้น

ผลคือถ้าบริการของโดเมนหนึ่งถูกเจาะ ผู้บุกรุกก็ยังถอดรหัสข้อมูลของโดเมนอื่นไม่ได้ เพราะกุญแจของโดเมนอื่นไม่ได้อยู่ในมือถึงแม้จะอยู่บนเครื่องเดียวกัน

ทำให้ของเก่ายังใช้ได้ระหว่างเปลี่ยน

การเปลี่ยนวิธีเข้ารหัสในระบบที่มีข้อมูลอยู่แล้วมีข้อบังคับหนึ่งข้อ — ต้องอ่านของเก่าได้ระหว่างที่ยังทยอยเปลี่ยน

เราจึงออกแบบรูปแบบข้อมูลที่เข้ารหัสให้ระบุชื่อกุญแจที่ใช้ไว้ในตัวมันเอง และให้ตัวถอดรหัสดูจากรูปแบบว่าเป็นของยุคไหนแล้วเลือกกุญแจให้ถูก

ข้อมูลที่เข้ารหัสด้วยวิธีเก่าจึงยังอ่านออกทั้งหมด ไม่ต้องหยุดระบบเพื่อแปลงทีเดียวทั้งก้อน

บั๊กที่ซ่อนอยู่จนวันที่เริ่มเข้ารหัสจริง

ตอนที่เราเปิดให้สร้างกุญแจให้โดเมนใหม่อัตโนมัติตอนสมัคร ระบบเริ่มพังทันทีตอนสร้างลูกค้าใหม่

ข้อความที่ขึ้นคือข้อผิดพลาดทั่วไปของการบันทึกข้อมูล ซึ่งไม่ได้บอกอะไรเลย

สาเหตุจริง

ข้อมูลที่เข้ารหัสแล้วมีความยาวกว่าที่คอลัมน์รองรับ

เพราะรูปแบบใหม่ประกอบด้วยหลายส่วนต่อกัน ทั้งเครื่องหมายบอกรุ่น ชื่อกุญแจ และตัวข้อมูลที่เข้ารหัสพร้อมข้อมูลประกอบ รวมแล้วรหัสผ่าน 16 ตัวอักษรกลายเป็นข้อความยาวเกือบ 90 ตัวอักษร ในขณะที่คอลัมน์รองรับได้ 50

ทำไมถึงไม่เคยพังมาก่อน

นี่คือส่วนที่น่าสนใจที่สุด

ความยาวเกินมีมาตั้งแต่ก่อนหน้านี้แล้ว แต่ไม่เคยถูกกระตุ้น เพราะกุญแจตั้งต้นไม่เคยถูกตั้งค่าจริงบนเครื่องใช้งาน

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

พอเปิดให้สร้างกุญแจอัตโนมัติ การเข้ารหัสก็ทำงานจริงเป็นครั้งแรก และบั๊กก็โผล่ทันที

สิ่งที่เราแก้ — สามอย่าง ไม่ใช่อย่างเดียว

  1. ขยายความกว้างคอลัมน์ ให้เผื่อไว้มากพอ โดยเขียนให้รันซ้ำได้ไม่เสียหาย
  2. ตรึงค่านี้ไว้ในตัวแบบข้อมูล เพื่อกันไม่ให้เครื่องมือสร้างโค้ดอัตโนมัติย้อนกลับไปเป็นค่าเดิมในอนาคต
  3. แก้ข้อความผิดพลาดให้บอกสาเหตุจริง — เดิมระบบแสดงเฉพาะข้อความชั้นนอกที่บอกแค่ว่า “เกิดข้อผิดพลาดขณะบันทึก” เราเปลี่ยนให้ไล่ดูสาเหตุที่ซ้อนอยู่ข้างในแล้วแสดงออกมาด้วย

ข้อที่สามไม่ได้แก้บั๊ก แต่แก้สิ่งที่ทำให้บั๊กนี้เสียเวลาไล่หานาน — และมันช่วยทุกบั๊กที่จะเกิดขึ้นในอนาคตบนเส้นทางเดียวกัน

เหตุการณ์ที่สอนมากที่สุด — หมุนกุญแจแล้วล้มกลางทาง

การหมุนกุญแจคือการเปลี่ยนไปใช้กุญแจดอกใหม่ ซึ่งต้องทำสองอย่างให้สำเร็จทั้งคู่

  1. เขียนไฟล์กุญแจใหม่ทับของเดิม
  2. ถอดรหัสข้อมูลเดิมด้วยกุญแจเก่าแล้วเข้ารหัสใหม่ด้วยกุญแจใหม่ แล้วบันทึก

ปัญหา

โค้ดเดิมทำข้อ 1 ก่อน แล้วค่อยทำข้อ 2

ระหว่างสองขั้นนั้นระบบอยู่ในสภาพที่ ไฟล์กุญแจเป็นดอกใหม่ แต่ข้อมูลในฐานข้อมูลยังเข้ารหัสด้วยดอกเก่า

ถ้าขั้นที่ 2 ล้มเหลวด้วยเหตุใดก็ตาม ระบบจะค้างอยู่ในสภาพนั้น — ทั้งโดเมนถอดรหัสรหัสผ่านฐานข้อมูลไม่ออก ซึ่งแปลว่าเชื่อมต่อฐานข้อมูลไม่ได้เลย

สิ่งที่เจ็บที่สุดของเรื่องนี้

โค้ดเดิมสำรองไฟล์กุญแจเก่าไว้แล้วตั้งแต่ต้น

แต่ไม่มีเส้นทางไหนในโปรแกรมที่เอามันกลับมาใช้เลย เมื่อเกิดข้อผิดพลาด ตัวดักจับชั้นนอกแค่แสดงข้อความแล้วจบ

พูดอีกอย่างคือ ระบบรู้วิธีกู้ตัวเอง แต่ไม่เคยกู้

เราคิดว่านี่เป็นบทเรียนที่ใช้ได้กว้างกว่าเรื่องกุญแจ — การสำรองข้อมูลที่ไม่มีเส้นทางกู้คืนที่ทดสอบแล้ว มีค่าน้อยกว่าที่ทุกคนคิด

วิธีแก้

  • ครอบขั้นที่ 2 ด้วยตัวดักจับของตัวเอง — ถ้าล้มเหลว ให้คัดไฟล์สำรองทับไฟล์กุญแจกลับทันที แล้วค่อยแจ้งข้อผิดพลาดต่อ เพราะข้อมูลในฐานข้อมูลยังเป็นของกุญแจเก่า การคืนไฟล์เก่าจึงทำให้ระบบกลับมาอ่านออกได้จริง ไม่ใช่แค่ลดความเสียหาย
  • ล้างข้อมูลที่ค้างอยู่ในหน่วยความจำก่อนกู้ — ไม่งั้นข้อมูลที่เข้ารหัสด้วยกุญแจใหม่ซึ่งค้างอยู่อาจหลุดไปถูกบันทึกในขั้นตอนถัดไปของคำขอเดียวกัน แล้วทำลายสิ่งที่เพิ่งกู้มา
  • ถ้ากู้ไม่สำเร็จ ให้บอกเป็นขั้นตอนว่าต้องคัดไฟล์ไหนทับไฟล์ไหน พร้อมรหัสอ้างอิง แทนที่จะแสดงข้อผิดพลาดดิบ ๆ ที่คนอ่านแล้วทำอะไรต่อไม่ถูก
  • ถ้าไม่มีไฟล์สำรอง (กรณีที่โดเมนนั้นไม่เคยมีกุญแจมาก่อน) ให้บอกตรง ๆ ว่าต้องไล่ตรวจข้อมูลที่ถอดรหัสไม่ออกเอง ไม่ใช่ปล่อยให้เข้าใจผิดว่ากู้ได้

สลับลำดับขั้นตอนอีกจุด

ระหว่างแก้เรื่องนี้เราพบอีกจุดหนึ่ง — ขั้นตอนเดิมรีสตาร์ตบริการก่อน แล้วค่อยนับว่ายังเหลือข้อมูลกี่รายการที่ยังใช้กุญแจเก่าอยู่

ผลคือคำเตือน “ยังมีข้อมูลอีก N รายการที่ถอดรหัสไม่ออก” โผล่มาหลังจากที่บริการถูกรีสตาร์ตไปแล้ว ซึ่งเป็นการกระทำที่ทำให้คำเตือนนั้นสำคัญ

สลับลำดับให้นับก่อนรีสตาร์ต คำเตือนจึงมาถึงตอนที่ยังตัดสินใจได้อยู่

ข้อความผิดพลาดที่ชี้ผิดทาง

ปัญหาที่ตามมาจากเรื่องกุญแจคือ เมื่อถอดรหัสไม่ได้ ระบบจะเข้าสู่สภาพที่แยกไม่ออกจากกรณีอื่นที่ต่างกันสิ้นเชิง

โค้ดเดิมยุบสามสาเหตุให้เหลือค่าว่างค่าเดียว — ไม่มีข้อมูลในระบบ · มีข้อมูลแต่ถอดรหัสไม่ได้ · ติดต่อฐานข้อมูลกลางไม่ได้เลย

หน้าจอจึงบอกทุกกรณีเหมือนกันว่า “ไม่พบข้อมูล กรุณาสร้างใหม่”

ซึ่งผิดและอันตราย ในกรณีที่พบบ่อยที่สุด — ข้อมูลมีอยู่แล้วแต่ถอดรหัสไม่ได้เพราะกุญแจถูกหมุนไป ผู้ดูแลที่ทำตามคำแนะนำบนหน้าจอจะสร้างข้อมูลใหม่ทับของเดิม

เราแยกให้เป็นสี่สาเหตุที่ต่างกัน พร้อมข้อความภาษาไทยที่บอกทางแก้ที่ตรงกับสาเหตุจริง — กรณีถอดรหัสไม่ได้จะบอกตรง ๆ ว่า “ข้อมูลมีอยู่แล้ว อย่าสร้างใหม่ ให้ไปที่หน้าจัดการกุญแจ”

สรุปสิ่งที่เราได้เรียนรู้

  1. การเข้ารหัสที่ไม่แยกขอบเขตป้องกันได้น้อยกว่าที่คิด — กุญแจดอกเดียวทั้งระบบแปลว่าความเสียหายจากการรั่วครั้งเดียวคือทุกราย
  2. โค้ดที่ไม่เคยทำงานจริงคือโค้ดที่ยังไม่รู้ว่าพัง — เส้นทางเข้ารหัสของเราถูกข้ามมาตลอดเพราะกุญแจไม่เคยถูกตั้ง บั๊กจึงรออยู่จนวันที่เปิดใช้จริง
  3. ขั้นตอนที่แก้ไขหลายอย่างต้องคิดเผื่อว่าล้มกลางทาง — และถ้าสำรองไว้แล้ว ต้องมีเส้นทางกู้คืนที่ทำงานจริง ไม่ใช่แค่มีไฟล์สำรองอยู่เฉย ๆ
  4. ข้อความผิดพลาดที่ชี้ผิดทางแย่กว่าไม่มีข้อความ — เพราะมันทำให้คนที่พยายามแก้ปัญหาลงมือทำสิ่งที่ทำให้แย่ลง

ทั้งสี่ข้อไม่ได้มาจากการอ่านคู่มือ แต่มาจากการที่ระบบพังจริงแล้วเราไล่ดูว่าทำไม

Freeable

บริหารจัดการข้อมูลในองค์กร ครบในที่เดียว

ดูรายละเอียด →

อ่านต่อ

Freeable

รหัสผ่าน 2026 — อักษรพิเศษ มาตรฐานสากล กฎหมายไทย และ 2FA/3FA ที่ควรรู้

กฎรหัสผ่านที่เราคุ้นเคย — ต้องมีตัวใหญ่ ตัวเล็ก ตัวเลข อักษรพิเศษ และเปลี่ยนทุก 90 วัน — ถูกมาตรฐานสากลถอดออกไปแล้ว บทความนี้รวบรวมว่าปัจจุบันมาตรฐานว่าอย่างไร กฎหมายไทยกำหนดอะไร และ 2FA ช่วยตรงไหนที่รหัสผ่านช่วยไม่ได้

Freeable

ค่าหนึ่งค่ามี 4 หน้าที่ — มาตรฐานการแทนค่า เก็บ · ส่ง · คำนวณ · แสดง

ปัญหาเรื่องวันที่ไม่ใช่ปัญหาของวันที่ แต่เป็นหนึ่งตัวอย่างของปัญหาตระกูลเดียวกัน — ค่าหนึ่งค่าถูกใช้ทำ 4 หน้าที่ที่ต่างกัน พอรูปแบบของหน้าที่หนึ่งรั่วไปอีกหน้าที่ ตัวเลขก็เพี้ยนเงียบ ๆ

Freeable

เวลาในระบบมีหลายชั้น และมันไม่ตรงกัน — บทเรียนจากบั๊กที่ไล่ 8 วันแล้วสรุปผิดหลายรอบ

บนเครื่องจริงของเรามีเขตเวลาอยู่ 3 ชั้นและไม่ตรงกันสักคู่ ทำให้ตัวเลขที่ดูเหมือนเทียบกันได้จริง ๆ เทียบไม่ได้ บทความนี้เล่าว่าเวลาซ่อนอยู่ที่ไหนบ้าง ทำไม "วันนี้" ถึงเป็นคำที่อันตราย และงานอัตโนมัติที่ค้าง 11 วันเพราะนาฬิกาเดินล้ำหน้า