คำแนะนำในการเก็บรหัสผ่านในระบบสำหรับนักพัฒนาซอฟต์แวร์ และผู้ดูแลระบบไอที

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

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

หลักของการเก็บรหัสผ่านในฐานข้อมูลนั้น

1. ไม่ใช่การเก็บตัวรหัสผ่านจริงๆ ลงไป

2. ไม่ควรใช้การจัดเก็บรหัสผ่านที่สามารถย้อนกลับมาเป็นรหัสผ่านต้นทางได้ ไม่ว่าจะทางใดก็ทางหนึ่ง

หลักง่ายๆ ก่อน 2 ข้อนี้ ทำให้เกิดวิธีคิดในการเก็บรหัสผ่านเพียงแค่ hash (หรือบางเอกสารเรียก fingerprint หรือค่า message digest) ของรหัสผ่านนั้นๆ กล่าวคือ การกระทำใดๆ ในตัวระบบ ต้องไม่มีความสามารถที่สามารถย้อนกลับวิธีการได้มาซึ่งข้อมูล hash ได้ (Non-invertibleเพื่อเป็นการป้องกันรหัสผ่านที่แท้จริงจากการนำไปใช้งานได้ทันทีหลังจากระบบถูก hack แล้วถูก dump ข้อมูลเหล่านี้ออกไป เพราะแม้ว่ารหัสผ่านที่ถูกนำออกไปจะเป็นเพียงแค่ hash ของข้อมูล แต่การโจมตีแบบ rainbow table attacks ก็สามารถถอดรหัสผ่านใดๆ ที่เป็นเพียงแค่ค่า hash ย้อนกลับมาเป็นรหัสผ่านเดิมได้ไม่ช้าก็เร็ว เพราะแม้มีความเป็นไปได้น้อยมากๆ แต่ก็ถือว่ามีความเสี่ยง

หลักการขอ rainbow table attacks คล้ายๆ การ brute force รหัสผ่านโดยทั่วไป แต่เป็นการกระทำต่อ hash เป็นหลัก โดยสุ่มชุดข้อมูลที่คิดว่าเป็นรหัสผ่าน มาเข้าขั้นตอน hash ที่เป็นที่นิยมใช้ให้ได้ซึ่งค่า hash แล้วเอาชุดข้อมูลดังกล่าว ใส่ลงในฐานข้อมูล rainbow tableไว้ แล้วเมื่อมีการ hack ระบบเกิดขึ้นแล้วได้ชุดข้อมูล hash ที่ dump ออกมา ก็เอาไปทดสอบเทียบกับชุดข้อมูลในฐานข้อมูลที่สร้างไว้ก่อนหน้านี้ ก็จะย้อนกลับมาได้ว่า ข้อมูล plaintext ที่เป็นส่วนย้อนกลับของ hash มีค่าใด

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

โดยด้านล่างเป็นลักษณะของฟังค์ชั่นโดยทั่วไปที่มักใช้กัน

[hash] = [salt] + [hash_function([salt] + [password])]

[salt] = เป็นการสุ่มจากวิธีการสุ่มใดๆ ที่ปลอดภัยที่สุดเท่าที่ทำได้ คำแนะนำคือควรใช้วิธีการสุ่มจากฟังค์ชั่นแบบ Cryptographically Secure Pseudo-Random Number Generator (CSPRNG)

[hash_function] ก็เลือกว่าจะเอาตัวไหนก็ได้ แต่ที่ใช้ๆ กันก็ แต่พวก MD5 หรือ SHA-1 ที่มันหาง่าย แต่มันก็แข็งแรงน้อยลงมากๆ ไม่แนะนำ และเดี่ยวนี้มันพูดกันที่ระดับ SHA-2 กันไปแล้ว (SHA-2 = SHA-256 หรือ SHA-512)

จริงๆ สูตรฟังค์ชันด้านบนนั้น มีชุดคำสั่งสำเร็จรูปที่นิยมกันที่ชื่อ PBKDF2 เพราะมีการกำหนดชุดการฟังคัชันในการ hash, จำนวนรอบในการสุ่ม และกำหนดความยาวของ hash ได้หลากหลาย ทำให้ยากมากขึ้นในการได้มากซึ่ง plaintext ที่แท้จริงจาก rainbow table

hash= PBKDF2(hash_function_name, password, salt, iterations, length)

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

โดยการทำแบบนี้ “ช่วยให้ผู้ใช้งานทั้งระบบยังพอมีเวลาในการปรับเปลี่ยนรหัสผ่านชุดใหม่ได้ใน ระยะเวลาที่น่าจะปลอดภัยมากที่สุด” เพราะหากว่ากันตามความเป็นจริงแล้ว ในวงการด้านการเข้ารหัสข้อมูลนั้น ทราบกันดีว่า ไม่มีวิธีการใดอะไรที่สามารถเข้ารหัสข้อมูลได้ปลอดภัยที่สุดไปตลอดกาล เพราะเทคโนโลยีด้านการคำนวนของ CPU/GPU นั้นเร็วมากขึ้นทุกวัน การจัดเก็บข้อมูลที่ปลอดภัยในช่วงเวลาหนึ่งอาจไม่ปลอดภัยในอีกไม่กี่ปีต่อมา เพราะเราสามารถแกะ และคำนวนหาค่าต่างๆ หรือสุ่มชุดข้อมูลต่างๆ ได้เร็วและหลายหลากขึ้น ตาม CPU/GPU ที่เร็วขึ้นเพื่อมาสร้าง rainbow table ได้ทุกขณะ

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

อ้างอิง

เว็บ se-ed.com เก็บรหัสผ่านสมาชิกของร้านเป็น plaintext!

เมื่อวานนั่งหาหนังสือ กะว่าจะสั่งหนังสือสัก 2-3 เล่ม แต่ลืมรหัสผ่าน se-ed.com เลยเข้า https://www.se-ed.com/forgot-password.aspx เพื่อขอขั้นตอนการปลดล็อคผ่านทางอีเมลเพื่อเข้าระบบ

2014-09-08_110337

 

แต่สิ่งที่ได้กลับมาทำให้ตกใจไม่น้อยเพราะ….

2014-09-08_110831

 

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

ส่วนเหตุผลว่าทำไมอ่านจากของเก่าได้ที่ อย่าไว้ใจเว็บแบรนด์ระดับโลกให้เก็บรหัสผ่านที่สำคัญของคุณ

ต่อไปรหัสผ่านอาจจะไม่จำเป็นสำหรับทุกๆ เว็บ

เรื่องรหัสผ่านนั้น มาในระยะหลังๆ ก็พบว่า บ้างเว็บก็เก็บรักษารหัสผ่านเราอย่างดี บ้างก็เก็บไว้ห่วยๆ นั้นยังไม่เท่าไหร่ (โดยเฉพาะเว็บของคนไทยหลายๆ เว็บ) แต่จากปัญหา Hearbleed ถึงแม้เว็บจะเก็บรหัสผ่านเราดีเพียงใด แต่ก็มีช่องโหว่ได้เช่นกัน ทำให้การให้เว็บต่างๆ เก็บรหัสผ่านเพื่อยืนยันการเข้าใช้ระบบต่างๆ นั้นเริ่มรู้สึกว่ามันจำเป็นน้อยลง เรื่อยๆ

ผมจึงมีแนวคิดที่เพิ่งคิดได้ว่าต่อไปทำเว็บอาจจะไม่จำเป็นต้องใช้รหัสผ่านแล้ว ใช้การเข้าระบบคล้ายๆ forgot password และมี activate link แทน หรือส่งเป็น OTP ผ่านมือถือแทนโดยใช้ลักษณะเป็นรายครั้ง โดยในส่วนของ OTP ผ่าน SMS นั้นแน่นอนว่าต้องขึ้นอยู่กับบริการแหละว่าแบบไหนควรใช้หรือไม่ควรใช้ ใช้อีเมลเป็นหลัก ส่วนบริการไหนมันซีเรียสมากๆ หรือลูกค้าที่จ่ายเงินใช้บริการ ก็คิดเป็นต้นทุนไป

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

อย่าไว้ใจเว็บแบรนด์ระดับโลกให้เก็บรหัสผ่านที่สำคัญของคุณ

จากกระทู้ต้นเรื่อง Starbucks Thailand ทำแบบนี้ได้ไง

ผมเลยลองทดสอบดูตามข้อมูลที่ https://www.starbuckscard.in.th/cards/forgot-password.aspx

2014-03-04_101523แล้วกรอกอีเมลที่ตัวเองได้ลงทะเบียนไว้แล้วพบว่ารหัสผ่านที่ส่งมานั้น ทาง Starbucks ส่งมาเป็น plaintext จริงๆ ตามข้อมูลด้านล่างนี้ (ผมขอนำรหัสผ่านจริงๆ ออกเพื่อประกอบการนำเสนอ และใส่ข้อความอื่นๆ แทน)

2014-03-04_101432แน่นอนว่าไม่ใช่แค่เว็บเท่านั้น เมื่อเกือบ 2 เดือนที่แล้ว Starbucks ก็ได้ทำพลาดแม้แต่ใน App ของตัวเองใน App Store เช่นกัน ตามรายการข่าวบางส่วน เช่น Starbucks: We Stored Your Passwords in Plaintext หรือ Starbucks App Saves Usernames, Passwords in Plain Text 

ซึ่งในความเป็นจริงแล้ว ระบบเว็บ หรือซอฟต์แวร์ต่างๆ โดยทั่วไปที่ใส่ใจต่อข้อมูลรหัสผ่าน ซึ่งเป็นข้อมูลที่อ่อนไหวง่ายที่สุด มักจะนำรหัสผ่านผู้ใช้งานไปผ่านกรรมวิธี hash ทางเดียว (one-way hashing; หรือลายเซ็นของข้อมูล) และใช้ salt ร่วมด้วย (ชุดอักขระสุ่มเฉพาะ) เพื่อความปลอดภัยสูงสุด การที่เว็บแบรนด์ดังจัดเก็บรหัสผ่านแบบ plain text หรือแม้แต่จัดเก็บแบบเข้ารหัสแต่สามารถย้อนกลับรหัสผ่านใดๆ ให้เป็น plain text ได้ ถือเป็นเรื่องที่ยอมรับไม่ได้ในวงการ Security ในด้านระบบยืนยันสิทธิ์ในการเข้าใช้ระบบ โดยสำหรับใครที่ไม่เข้าใจกรรมวิธี hash และใช้ salt ร่วมด้วย แนะนำให้อ่าน Hash: ไม่รู้ว่ามันคืออะไรแต่มันใช่ เผื่อจะเข้าใจมากขึ้น ว่าสิ่งที่ Starbucks กำลังทำอยู่นั้นเป็นสิ่งที่ยอมรับไม่ได้ และสามารถดูตัวอย่างเว็บที่ไม่ใส่ใจกับข้อมูลอ่อนไหวเหล่านี้ได้ที่ Plain Text Offenders

ฉะนั้นจากเหตุการณ์นี้ หลายคนอาจจะยังไม่เข้าใจปัญหาที่อาจจะเกิดขึ้นในอนาคต ผมจึงขอยกตัวอย่างง่ายๆ ว่าในอนาคตหากเว็บ Starbucks ถูก hack และเหล่าผู้ไม่ประสงค์ดีได้ทำการ dump ข้อมูลลูกค้าพร้อมรหัสผ่านออกไป การไม่คงสภาพรหัสผ่านที่สามารถย้อนกลับมาเป็น plain text ได้ จะช่วยปกป้องให้รหัสผ่านต่างๆ ของลูกค้าของตัวเองยังคงปลอดภัยอยู่สักระยะจากการใช้วิศวกรรมย้อนกลับ เพราะต้องใช้เวลาในการคำนวณ และกู้สภาพย้อนกลับผ่าน rainbow table (หรือการทำ rainbow hash cracking) แน่นอนว่าการใช้ salt ร่วมด้วยก็ช่วยได้ในระดับที่น่าพอใจ ซึ่งดีกว่าการจัดเก็บรหัสผ่านเป็นข้อมูล plain text ซึ่งผู้ไม่ประสงค์ดีสามารถนำไปใช้ได้เลยโดยไม่จำเป็นต้องใช้เทคนิคพิเศษใดๆ

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

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

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

ข้อคิดบางอย่างที่ได้หลังจากเหตุการณ์ Drupal.org ถูกแฮก

จาก

Important Security Update: Reset Your Drupal.org Password

Drupal.org ถูกแฮก รีเซ็ตรหัสผ่านผู้ใช้ทุกคน

เหตุการณ์ที่ Drupal.org ถูกแฮกนั้น เกิดจากเครื่องมือของผู้ให้บริการระบบที่ Drupal.org ที่ใช้บริการอยู่นั้นมีช่องโหว่ ทำให้ผู้เจาะระบบสามารถเข้าถึงฐานข้อมูลได้ โดยปัญหาที่เกิดขึ้นนี้ไม่ใช่ช่องโหว่ของ Drupal โดยตรงแต่อย่างใด ผู้ใช้งาน Drupal อยู่ตอนนี้สบายใจได้ (แต่ยังแนะนำให้ upgrade ตัว Drupal 7 ให้ไปใช้ Drupal 7.22 ซึ่งเป็นตัวล่าสุด)

สำหรับคนที่เป็นสมาชิก Drupal.org แบบผม ถึงแม้จะเอาข้อมูลผู้ใช้งานไปได้ แต่รหัสผ่านที่บันทึกไว้นั้นยังถูกนำไปผ่านกรรมวิธี hash และใช้ salt ร่วมด้วยเพื่อให้ได้ชุดข้อมูลเชิงเปรียบเทียบทางเดียว (ไม่สามารถแปลงกลับเป็นรหัสผ่านจริงๆ ได้อีก) แต่ก็มีรหัสผ่านบางส่วน (ที่เก่ามากๆ) มีแต่ hash อย่างเดียว (เป็นส่วนน้อย) จึงยังคงมีความปลอดภัยอยู่

แต่ทาง Drupal.org ยังแนะนำให้เข้าไปตั้งรหัสผ่านใหม่ เพื่อทำการสร้างชุด hash และ salt ใหม่อีกครั้งเพื่อความปลอดภัยและเพื่อป้องกันการใช้ชุดข้อมูลรหัสผ่านที่ถูกขโมยไปแล้ว ถูกนำไปผ่านกรรมวิธี rainbow hash cracking หรือการนำรหัสผ่านที่ได้จาก hash function ที่ยอดนิยมอย่าง md5 หรือ sha1 มาเปรียบเทียบกับ rainbow table แล้วย้อนกลับเป็นรหัสผ่านจริงๆ ได้อีกครั้ง โดยมักจะมีปัญหากับการใช้ hash กับรหัสผ่านโดยไม่มี salt มาช่วยในการ hash ตัวรหัสผ่านอีกรอบ

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