การจัดเก็บรหัสผ่านสามารถทำได้หลากหลายรูปแบบ, วิธี, รวมถึงนโยบายในการรับอักขระต่างๆที่แตกต่างกันไป แต่ถ้าหากออกแบบกระบวนการเหล่านี้ไม่ดีพอก็จะทำให้มีปัญหาตามมาอย่างมาก เช่น ถูกสุ่มเดาได้ง่าย, เมื่อฐานข้อมูลถูกเจาะ ข้อมูลผู้ใช้ทั้งหมดรั่วไหลและถูกเปิดเผยทันที, ไม่รองรับกับแอปพลิเคชันช่วยสร้างรหัสผ่านที่มีความปลอดภัยสูง, ฯลฯ ต่างๆเหล่านี้เป็นต้น. ดังนั้นแล้วกระบวนการต่างๆเหล่านี้จึงต้องมีการออกแบบและจัดเก็บที่เหมาะสม เพื่อปกป้องผู้ใช้ของคุณอย่างสูงสุด. ทั้งนี้ข้อมูลต่างๆเหล่านี้ นำมาจากแหล่งอ้างอิงต่างๆที่น่าเชื่อถือโดยผู้มีประสบการณ์จากทั่วโลกได้ให้ข้อมูลไว้ ข้อมูลใดที่เป็นความเห็นของผู้เขียนเองจะมีการวงเล็บบอกไว้.
การรับอักขระของรหัสผ่าน
ข้อมูลต่อไปนี้เป็นคำแนะนำในขั้นตอนการตรวจสอบรับข้อมูลรหัสผ่านโดยที่ยังไม่ผ่านการ hash ใดๆก่อน เพื่อตรวจสอบให้เป็นไปตามเงื่อนไขความปลอดภัย.
คำว่ารับหรือไม่รับอักขระ หมายถึงตัวอักษรเป็นตัวๆ, คำว่ารับหรือไม่รับรหัสผ่าน หมายถึงตัวอักษรทั้งหมดที่กรอกผ่านฟอร์มรหัสผ่าน.
- รหัสผ่านต้องมีความยาวมากกว่า 3 ตัวอักษร (จากคห.ของผู้เขียน - กรณีในขั้นตอนพัฒนาซอฟต์แวร์บนเครื่อง เพื่อความสะดวกไม่ต้องพิมพ์ยาวนัก).
- รหัสผ่านควรมีความยาวตั้งแต่หรือมากกว่า 8 ตัวอักษรขึ้นไป (จากคห. ของผู้เขียน - อาจเปลี่ยนจากควรมีเป็นต้องมี คือ บังคับให้ยาวตั้งแต่ 8 ตัวอักษรขึ้นไป สำหรับระบบที่ต้องการความปลอดภัยสูง).
- ไม่ควรจำกัดความยาวของอักขระ หรือจำกัดไม่เกิน 72 ไบต์สำหรับ bcrypt. ตัวอย่างเช่น อักขระภาษาไทยจะใช้ประมาณ 3 ไบต์ ถ้าจะรับทั้งหมด 10 ตัวจะใช้ประมาณ 30 ไบต์, อักขระ emoji จะใช้ 4 ไบต์ ถ้าใช้ผสมกันก็ต้องนับเผื่อจากมากที่สุดคือตัวละ 4 ไบต์ โดยทั้งหมด 72 ไบต์สำหรับ bcrypt จะได้ 18 ตัวอักษร. ทั้งนี้หากเก็บข้อมูลโดยใช้ hash รูปแบบอื่น ข้อจำกัดจะเปลี่ยนไป โดยจะเก็บได้มากขึ้น แต่โดยหลักการทั่วไปไม่ควรให้เกิน 100 ตัวอักษร เพราะจะเกินความจำเป็น.
- ควรรับอักขระต่อไปนี้ โดยไม่จำเป็นต้องมีครบทุกเงื่อนไขก็ได้ (จากคห.ของผู้เขียน - เราควรสนับสนุนการตั้งรหัสผ่านอย่างเสรี และเน้นไปที่ความยาวมากกว่าที่จะไปบังคับให้ผู้ใช้ตั้งสิ่งที่จำได้ยาก จนกระทั่งสุดท้ายผลักเขาไปตั้งรหัสที่เหมือนจะจำยากแต่เดาง่ายแทน เช่น
pA55w+rd
).- ต้องรับอักขระภาษาอังกฤษ ตัวเล็กและตัวใหญ่มีความต่างกัน.
- ต้องรับอักขระที่เป็นตัวเลข โดยจะมีตัวเดียวหรือมากกว่าก็ได้.
- ต้องรับอักขระที่เป็นตัวอักษรพิเศษ โดยจะมีตัวเดียวหรือมากกว่าก็ได้ เช่น ( ) ' " ! @ # $ % เป็นต้น.
- ต้องรับอักขระที่เป็นเครื่องหมายคณิตศาสตร์ โดยจะมีตัวเดียวหรือมากกว่าก็ได้ เช่น + - * / เป็นต้น.
- ควรรับอักขระที่เป็นสัญลักษณ์ต่างๆ โดยจะมีตัวเดียวหรือมากกว่าก็ได้ เช่น ✿ 🚗 🛩 🏢 ▶ ⟰ เป็นต้น.
- ควรรับอักขระที่เป็น unicode เช่น ตัวอักษรภาษาไทย, ภาษาจีน, ภาษาญี่ปุ่น เป็นต้น.
- ควรรับอักขระที่เป็นช่องว่าง (space) ปะปนอยู่กับอักขระอื่นๆตามเงื่อนไขด้านบน.
- ห้ามรับอักขระที่เป็นช่องว่างล้วน (space) โดยไม่มีอักขระอื่นๆเลย.
- ไม่ควรรับรหัสผ่านที่อยู่ในรายการต้องห้าม เนื่องจากไม่มีความปลอดภัย ตัวอย่างรายการต้องห้าม (จากคห.ของผู้เขียน - ทั้งนี้อาจจะห้ามไปเลยถ้าหากระบบนั้นต้องการความปลอดภัยมากขึ้น).
- ห้ามรับรหัสผ่านที่ตรงกับข้อมูลผู้ใช้อื่นๆ เช่น ตรงกับอีเมล, ตรงกับชื่อผู้ใช้ เป็นต้น.
- ห้ามป้องกันการ copy & paste รหัสผ่าน เนื่องจากผู้ใช้จำนวนมากใช้วิธีสร้างรหัสผ่านจากแอปพลิเคชันหรือปลั๊กอิน โดยให้สร้างรหัสผ่านที่ยาวและจำได้ยาก (เดาได้ยากด้วย) ซึ่งต้องอาศัยการ copy & paste เท่านั้น. การป้องกัน copy & paste จะทำให้เป็นอุปสรรคและบังคับให้ผู้ใช้หันไปตั้งรหัสผ่านที่พิมพ์ง่ายๆจำง่ายๆแทน ซึ่งกลายเป็นอันตรายมากกว่ามีผลดี.
การเก็บรหัสผ่าน
- ต้องถูกผ่านการ hash (เพื่อที่จะให้อ่านไม่ได้) ทางเดียวเท่านั้น จะต้องไม่สามารถถูกทำย้อนกลับมาในสภาพที่อ่านได้อีก.
- ควรผ่านการ hash โดยใช้วิธีการ (algorithm) ใดวิธีหนึ่งเหล่านี้. ตัวเลือกจากด้านบนสุดคือดีที่สุด ตามลำดับ.
- Argon2
- PBKDF2
- scrypt
- bcrypt
สำหรับผู้เขียนภาษา PHP
- ควรศึกษาฟังก์ชั่นเหล่านี้.
- ไม่ควรใช้ฟังก์ชั่นอื่นๆของ PHP ที่ไม่มีกำหนดเวลาการประมวลผล (time cost) ในการ hash อีกต่อไป เช่น
md5()
,sha1()
เป็นต้น.
นโยบายด้านความปลอดภัยต่างๆ
สำหรับผู้พัฒนาระบบที่ต้องการความปลอดภัยสูงมากขึ้น แนะนำให้เพิ่มเติมและหลีกเลี่ยงสิ่งเหล่านี้ตามความเหมาะสม.
- ไม่ควรกำหนดอายุรหัสผ่าน เช่น ให้เปลี่ยนรหัสผ่านทุกๆ 90 วัน เป็นต้น เพราะจะสร้างความรำคาญอย่างมากให้กับผู้ใช้ และผลักให้ผู้ใช้ต้องตั้งรหัสผ่านที่ง่ายๆ, หรือไม่ปลอดภัย เพื่อตัดความน่ารำคาญนี้. (จากคห.ของผู้เขียน - ไม่แนะนำอย่างยิ่ง เนื่องจากถ้าไม่มีการป้องกันที่ดีพอก็ถูกเจาะได้ในเวลารวดเร็วอยู่ดี).
- ควรมีการป้องกันสุ่มโจมตีรหัสผ่าน (brute-force attack). โดยหลักการคือ ผู้โจมตีจะรู้ชื่อผู้ใช้ แล้วเขียนโปรแกรมขึ้นมาสุ่มรหัสผ่านยิงเข้าฟอร์ม ทำไปเรื่อยๆจนกว่าจะถูก. วิธีการโจมตีแบบนี้สามารถทำได้โดยสุ่มรหัสผ่านจำนวนมากในเวลา 1 วินาที, การป้องกันเช่น เมื่อผิดพลาดเกิน 3 ครั้งให้รอ 15 นาที เป็นต้น. หรือศึกษาเพิ่มเติมจากตัวอย่าง PHP device cookies.
- ควรมีการกรองบอท (bot) ออกไป. วิธีนี้อาจใช้เทคนิค captcha, honeypot เข้ามาช่วย.
- อาจจะเก็บรหัสผ่านเก่าทุกครั้งที่มีการเปลี่ยนรหัสผ่านใหม่ (ในรูปแบบ hash) และป้องกันไม่ให้รหัสผ่านเก่าถูกนำมาใช้อีก (จากคห.ของผู้เขียน - วิธีนี้ดูเหมือนเว็บไซต์ ebay.com จะใช้อยู่ ซึ่งมันก็ช่วยป้องกันไม่ให้ใช้รหัสผ่านเก่าที่อาจถูกเปิดเผยหรือรั่วไหลไปแล้วได้ดี).
- ควรใช้การตรวจสอบขั้นที่ 2 (ศึกษาได้จากคำค้น 2 Factor authentication, Multi factor authentication, OTP).
- อาจใช้แอปพลิเคชันบนมือถือ เช่น Authenticator หรืออาจะใช้วิธีสร้างตัวเลขไม่เกิน 9 หลักส่งไปทางอีเมล (email), SMS แล้วให้กรอกค่านี้ให้ถูกต้อง.
- ต้องกำหนดอายุของมันด้วย เช่น ให้กรอกภายใน 5 นาทีเป็นต้น.
กรณีลืมรหัสผ่าน
- ห้ามใช้คำแนะนำ (hint) เมื่อลืมรหัสผ่าน. เพราะกรณีเลวร้ายเคยเกิดขึ้นมาแล้วในอดีต.
- ไม่ควรใช้คำถามเมื่อลืมรหัสผ่าน. การให้ตอบคำถามเมื่อลืมรหัสผ่านไม่ช่วยอะไรเลยในเรื่องความปลอดภัย และจะทำให้ถูกเข้าสู่ระบบโดยผู้โจมตีได้ง่ายขึ้นอีก ตัวอย่างเช่น นาย ก มีเพื่อนคือ นาย ข, นาย ก ไม่ต้องการให้นาย ข มาเข้าสู่ระบบเพื่อซื้อของ แต่เพราะนาย ข สนิทกับนาย ก จึงสามารถตอบคำถามส่วนตัวเมื่อลืมรหัสผ่านได้ถูกต้องทั้งหมด ทำให้นาย ข แอบเข้าสู่ระบบได้เลยทันที.
- ควรใช้วิธีการตั้งค่ารหัสผ่านใหม่ (reset password).
- ใช้การส่งลิ้งค์ไปทางอีเมลเจ้าของบัญชีเพื่อตั้งค่ารหัสผ่านใหม่.
- ต้องมีค่าเฉพาะแนบไปกับลิ้งค์ เพื่อป้องกันการเรียกโดยตรง.
- ต้องกำหนดอายุของมันด้วย เช่น ให้กรอกภายใน 5 นาทีเป็นต้น.
- หรือใช้การส่งรหัสผ่านครั้งเดียว (OTP) ทาง SMS เพื่อตั้งค่ารหัสผ่านใหม่.
- ต้องกำหนดอายุของมันด้วย เช่น ให้กรอกภายใน 5 นาทีเป็นต้น.
- ใช้การส่งลิ้งค์ไปทางอีเมลเจ้าของบัญชีเพื่อตั้งค่ารหัสผ่านใหม่.
ควบคุม session การเข้าสู่ระบบ
- ควรเก็บประวัติการเข้าสู่ระบบโดยละเอียด เช่น วัน-เวลา, สถานที่, หมายเลขไอพี เป็นต้น.
- อาจจะกำหนดให้ 1 ผู้ใช้เข้าสู่ระบบได้เพียง 1 session เช่น เข้าสู่ระบบบนคอมพิวเตอร์เครื่องเดียวกันแต่ใช้ Firefox ก็จะเข้าอีกโดยใช้ Chrome ไม่ได้.
- ควรให้ควบคุมการเข้าสู่ระบบ หรือบังคับให้ออกจากระบบได้โดยผู้ใช้นั้นๆ กรณีอนุญาตให้เข้าสู่ระบบได้มากกว่า 1 session. ตัวอย่างเช่น ผู้ใช้ ก เข้าสู่ระบบจากคอมพิวเตอร์ที่บ้านในกรุงเทพฯ จากนั้นไปเที่ยวเชียงใหม่และเข้าสู่ระบบจากคอมพิวเตอร์ของโรงแรมแล้วลืมออกจากระบบ ผู้ใช้ ก สามารถเข้าสู่ระบบบนมือถือแล้วสั่งให้ออกจากระบบทั้งหมด หรือออกจากระบบเฉพาะเครื่องคอมพิวเตอร์ที่โรงแรมก็ได้.
อ้างอิง
- Password length & complexity
- Password policy
- Password Storage Cheat Sheet
- 2016 NIST’s new password rules
- Digital identity guidelines
- Password Rules Are Bullshit
- password complexity policy for non “English” passwords
- what are good requirements for a password
- PHP Security: Passwords
- 9 Password Storage Best Practices