สวัสดีครับ ช่วงนี้ข่าวสารเกี่ยวกับความปลอดภัยมาแรงเหลือเกิน เมื่อไม่นานมานี้ก็มีข่าวว่าเว็บ drupal.org ถูกแฮ็กเกอร์เจาะเข้าไปอ่านฐานข้อมูลของผู้ใช้ หรือแม้แต่ facebook และ instagram เองก็มีข่าวพบช่องโหว่ออกมาเนืองๆ ทำให้บรรดาผู้ใช้งานเสี่ยงต่อการถูกขโมยข้อมูลและรหัสผ่านกันถ้วนหน้า
คำแนะนำที่หาได้ทั่วไปมักจะเป็นให้ผู้ใช้ระมัดระวังตัวเอง ฝึกตัวเองให้รอบคอบ ไม่เข้าเว็บที่สุ่มเสี่ยงต่อการติดมัลแวร์ ติดตั้งไฟล์วอลล์ ติดตั้ง antivirus หมั่นสแกนเครื่องคอมพิวเตอร์อยู่เสมอ อัพเดตระบบปฏิบัติการ ตั้งรหัสผ่านที่คาดเดาได้ยาก เปลี่ยนรหัสผ่านเป็นประจำ ติดตามข่าวสารแค่อ่านก็เหนื่อยแทนแล้ว แถมใช่ว่าปฏิบัติตามแล้วจะปลอดภัย 100% อย่างเมื่อเดือนที่ผ่านมา เว็บไซต์หนังสือพิมพ์ และเว็บไซต์ธนาคารหลายแห่งของประเทศไทยถูกเจาะเพื่อวางโทรจันสำหรับขโมยข้อมูลของผู้ใช้งาน ผู้ใช้งานที่ไม่รู้อิโหน่อิเหน่เมื่อเข้าไปทำธุรกรรมทางการเงินก็อาจโดนขโมยข้อมูลไปได้
การที่กรรมกรเขียนโปรแกรมอย่างพวกเราจะปล่อยให้ผู้ใช้ตาดำๆ เหน็บสากออกไปสู้กับกองทัพแฮ็กเกอร์หิวกระหายข้อมูลส่วนบุคคลมันก็ดูโหดร้ายไปหน่อย สัปดาห์นี้เลยนำเสนอวิธีการเก็บรหัสผ่านของผู้ใช้งานในระบบให้ปลอดภัย ถึงแม้ระบบอาจจะโดนเจาะไปแต่สิ่งที่แฮ็กเกอร์ได้ไปจะเอาไปใช้งานไม่ได้ทำให้ผู้ใช้งานระบบมีความปลอดภัยมากขึ้น(บ้าง)
ข้อแนะนำสำหรับการเก็บรหัสผ่าน
1. อย่าเก็บรหัสผ่านในแบบ plaintext
โปรแกรมเมอร์มือใหม่ทั้งหลายมักชอบเก็บรหัสผ่านในแบบ plaintext เพราะ เขียนง่าย อ่านง่าย และตรวจสอบสิทธิ์ง่าย แต่หารู้ไม่ว่าการเก็บแบบนี้ถือว่าไม่ปลอดภัยอย่างยิ่ง หากผู้โจมตีสามารถเข้าถึงไฟล์หรือฐานข้อมูลที่เก็บรหัสผ่านได้ รหัสผ่านทั้งหมดจะถูกขโมยทันที ถึงแม้จะเข้ารหัสไฟล์หรือฐานข้อมูลเอาไว้ก็ตามก็ยังไม่ปลอดภัยอยู่ดี ตัวอย่างเช่น SQL Server 2005 ที่มีการเข้ารหัสป้องกันข้อมูลในฐานข้อมูล สมมติว่ามีผู้ใช้ที่มีสิทธิ์ในการเข้าถึงฐานข้อมูลต้องการขโมยข้อมูล ผู้ใช้ดังกล่าวจะใช้คำสั่ง SELECT เพื่อดึงข้อมูลออกมาโดย SQL Server จะทำการถอดรหัสข้อมูลมาให้แบบอัตโนมัติ
นอกจากนี้ ในระหว่างการตรวจสอบสิทธิ์ หากมีการส่งข้อมูลผ่านระบบเครือข่าย รหัสผ่านในรูป plaintext จะถูกมองเห็นได้ง่ายมาก แม้จะใช้ระบบเครือข่ายที่มีความมั่นคงปลอดภัยสูง ตัวอย่างเช่น ระบบที่ใช้ SSL ในการส่งรหัสผ่านไปตรวจสอบยังเครื่องแม่ข่าย ถ้าหากเครื่องแม่ข่ายทำการดึงข้อมูลจากฐานข้อมูลทางไกลออกมาเพื่อตรวจสอบ ข้อมูลที่ถูกดึงออกมาเพื่อส่งให้เครื่องแม่ข่ายจะถูกถอดรหัสและส่งไปยังเครื่องแม่ข่าย ทำให้ไม่ปลอดภัยอยู่ดี
2. เข้ารหัสก่อนจะเก็บลงฐานข้อมูล
วิธีนี้ดีขึ้นกว่าการเก็บรหัสผ่านในแบบ plaintext ขึ้นมาเล็กน้อย ขั้นตอนคือนำรหัสผ่านของผู้ใช้ไปเข้ารหัสด้วยอัลกอริทึมเข้ารหัสเช่น AES หรือ Triple-DES เป็นต้น จากนั้นจึงเก็บผลลัพท์ที่ได้จากการเข้ารหัสแทนการเก็บรหัสผ่านแบบตรงๆ เมื่อต้องการตรวจสอบสิทธิ์ของผู้ใช้สามารถทำได้ 2 วิธีคือ
- นำรหัสผ่านที่เก็บอยู่ในฐานข้อมูลออกมา ทำการถอดรหัส และเปรียบเทียบกับรหัสผ่านที่ผู้ใช้ส่งมา
- นำรหัสผ่านที่ผู้ใช้ส่งมาเข้ารหัส แล้วนำไปเปรียบเทียบกับรหัสผ่านที่เก็บอยู่ในฐานข้อมูล
ข้อดี:
เมื่อผู้ใช้ลืมรหัสผ่าน ผู้ดูแลระบบสามารถกู้รหัสผ่านอย่างง่ายดาย
ข้อเสีย:
- เนื่องจากอัลกอริทึมเข้ารหัสต้องอาศัยกุญแจในการเข้า/ถอดรหัส ซึ่งกุญแจนี้จะถูกต้องเก็บเป็นความลับ แฮ็กเกอร์ก็จะเปลี่ยนเป้าหมายจากการหารหัสผ่าน เป็นการหากุญแจสำหรับอัลกอริทึมเข้า/ถอดรหัสแทน ถ้าแฮ็กเกอร์ได้กุญแจไป รหัสผ่านที่เก็บไว้ทั้งหมดจะถูกอ่านได้ทันที ดังนั้นปัญหาที่ว่าเก็บรหัสผ่านอย่างไร จะกลายเป็นปัญหาว่าจะเก็บกุญแจสำหรับเข้ารหัสอย่างไรแทน ซึ่งกุญแจสำหรับอัลกอริทึมเข้า/ถอดรหัสดังกล่าวไม่สามารถเขียนฝังไว้ในโปรแกรมได้ตรงๆ เพราะแฮ็กเกอร์สามารถหาข้อมูลจาก PE file ได้เสมอ (แต่ถ้ามองในแง่ดีการเก็บกุญแจ 10 ดอกให้ปลอดภัยยังง่ายกว่าการเก็บรหัสผ่านของผู้ใช้ 100 คนให้ปลอดภัยนะ)
- หากใช้อัลกอริทึมเข้ารหัสแบบบล็อก (Block Cipher) จะต้องมีการเก็บความยาวของรหัสผ่านเอาไว้ด้วย เพราะอัลกอริทึมเข้ารหัสแบบบล็อคจะเข้ารหัสข้อมูลที่มีความยาวตามที่กำหนดไว้ ดังนั้นจึงต้องทำการ padding ข้อมูลเพื่อให้ได้ความยาวตามที่ต้องการก่อนเข้ารหัส และเมื่อถอดรหัสแล้วจะต้องอาศัยความยาวของรหัสผ่านเป็นตัวบอกว่ารหัสผ่านดั้งเดิมมีความยาวเท่าใดและถอดตัว padding ทิ้ง โปรดจำเอาไว้ว่าความยาวของรหัสผ่านเป็นข้อมูลที่สำคัญมาก หากแฮ็กเกอร์ทราบความยาวของรหัสผ่านจะช่วยให้การเดารหัสผ่านทำได้ง่ายขึ้นมาก
- การตรวจสอบสิทธิ์ผ่านระบบเครือข่ายจำเป็นต้องมีการส่งรหัสผ่านในรูป plaintext ไปยังเครื่องแม่ข่ายหรือส่งกุญแจไปยังเครื่องผู้ใช้เพื่อให้เข้ารหัสก่อนส่งมายังเครื่องแม่ข่าย ดังนั้นรหัสผ่านหรือกุญแจอาจรั่วไหลได้
- ถ้ามีผู้ใช้ที่ใช้รหัสผ่านเดียวกัน จะทำให้ผลลัพธ์ที่ได้จากการเข้ารหัสมีค่าเดียวกัน สามารถแก้ได้โดยใช้ SALT (ดูข้อแนะนำที่ 4)
แล้วควรจะใช้วิธีนี้เมื่อใด:
เมื่อความต้องการหลักของโปรแกรมคือต้องสามารถกู้รหัสผ่านที่ผู้ใช้ลืมได้ วิธีนี้แทบจะเป็นวิธีเดียวที่สามารถกู้รหัสผ่านคืนได้ 100% และยังสามารถเก็บรหัสผ่านได้อย่างปลอดภัย แต่ต้องอย่าลืมหาที่เก็บกุญแจสำหรับเข้ารหัสไว้ในที่ปลอดภัย รวมทั้งต้องใช้อัลกอริทึมเข้ารหัสที่มีความปลอดภัยสูง
3. เก็บค่าแฮชของรหัสผ่าน
ฟังก์ชั่นแฮช คืออัลกอริทึมที่รับข้อมูลนำเข้าความยาวเท่าใดก็ได้ จากนั้นจะเปลี่ยนให้เป็นผลลัพท์ที่มีความยาวคงที่ที่มีความจำเพาะของแต่ละข้อมูล และกระบวนการย้อนหาค่าย้อนคืนของข้อมูลนำเข้าจะต้องทำได้ยาก (ถ้าจะให้ดีคือต้องไม่สามารถหาค่าย้อนคืนได้) กล่าวคือข้อมูลนำเข้าแต่ละตัว (ที่มีค่าไม่ซ้ำกัน) ควรผ่านฟังก์ชั่นแฮชแล้วได้ค่าไม่ซ้ำกัน และไม่สามารถหาค่าย้อนคืนจากค่าแฮชได้ ตัวอย่างของฟังก์ชั่นแฮชยอดนิยมคือ MD5 และ SHA2
สำหรับขั้นตอนในการเก็บรหัสผ่านโดยใช้ฟังก์ชั่นแฮชนั้น ทำโดยนำรหัสผ่านไปคำนวณด้วยฟังก์ชั่นแฮชและเก็บค่าที่ได้หลังจากผ่านฟังก์ชั่นแฮช (ค่าแฮช) แทนการเก็บรหัสผ่านตรงๆ ในการตรวจสอบสิทธิ์ของผู้ใช้ ให้นำรหัสผ่านที่ระบบได้รับมาผ่านฟังก์ชั่นแฮช และนำค่าที่ได้ไปเปรียบเทียบกับค่าแฮชที่เก็บไว้ ถ้าค่าแฮชของรหัสผ่านที่ส่งมาตรงกับค่าแฮชที่เก็บไว้แสดงว่ารหัสผ่านของผู้ใช้ถูกต้อง
ข้อดี:
- ฟังก์ชั่นแฮชที่ใช้สามารถประกาศให้ทุกคนรู้ได้
- การหาค่าย้อนคืนของรหัสผ่านจากค่าแฮชทำได้ยากมาก ส่งผลให้รหัสผ่านจริงรั่วไหลได้ยากกว่าเดิม
- ไม่มีการเก็บรหัสผ่านจริงเอาไว้ ดังนั้นถึงแม้ฐานข้อมูลที่เก็บค่าแฮชไว้จะถูกขโมยไป แต่สิ่งที่ได้ไปจะเป็นค่าค่าแฮชเท่านั้น
- ไม่จำเป็นต้องเก็บความยาวของรหัสผ่าน ทำให้การเดารหัสผ่านทำได้ยากกว่าเดิม
- ไม่ต้องกังวลเรื่องการเก็บกุญแจสำหรับเข้า/ถอดรหัสเหมือนวิธีแรก เพราะการใช้ฟังก์ชั่นแฮชไม่จำเป็นต้องใช้กุญแจ
- การตรวจสอบสิทธิ์ผ่านระบบเครือข่ายสามารถทำได้โดยไม่จำเป็นต้องส่งรหัสผ่านในรูป plaintext เพียงแค่ให้ผู้ใช้นำรหัสผ่านของตนผ่านฟังก์ชั่นแฮชที่ประกาศไว้ แล้วส่งค่าแฮชมายังเครื่องแม่ข่าย ดังนั้นสิ่งที่แฮ็กเกอร์สามารถดักจับได้จะมีเพียงค่าแฮชเท่านั้น
ข้อเสีย:
- เมื่อผู้ใช้ทำรหัสผ่านหายจะไม่สามารถกู้คืนได้
- ถ้ามีผู้ใช้ที่ใช้รหัสผ่านเดียวกัน จะทำให้ค่าแฮชที่ได้มีค่าเหมือนกัน สามารถแก้ได้โดยใช้ SALT (ดูข้อแนะนำที่ 4)
ควรจะใช้วิธีนี้เมื่อใด:
วิธีนี้มีความปลอดภัยสูง แต่ต้องระวังในการเลือกใช้ฟังก์ชั่นแฮช ควรเลือกใช้ฟังก์ชั่นแฮชที่มีความปลอดภัยสูง เช่น SHA-2 (ไม่แนะนำให้ใช้ SHA-1 และ MD5) และควรใช้งานควบคู่กับการใช้ SALT
4. ข้อแนะนำในการเก็บความยาวของรหัสผ่าน
วิธีการเข้ารหัสก่อนเก็บลงฐานข้อมูลจำเป็นจะต้องเก็บความยาวเอาไว้เมื่อใช้อัลกอริทึมเข้ารหัสแบบบล็อค แต่ความยาวของรหัสผ่านเป็นข้อมูลที่มีความสำคัญมาก เพราะถ้าหากข้อมูลนี้ถูกล่วงรู้โดยแฮ็กเกอร์ จะช่วยให้แฮ็กเกอร์ตัดรหัสผ่านที่เป็นไปไม่ได้ออกเป็นจำนวนมาก ตัวอย่างเช่น หากแฮ็กเกอร์รู้ว่ารหัสผ่านนี้ยาว 5 จะทำให้เหลือรหัสผ่านที่ต้องค้นหาเป็นจำนวน 945 = 7,339,040,224 รหัส (พิจารณาจากจำนวนตัวอักษรทั้งหมดบนคีย์บอร์ดแบบ QWERTY)
ปัญหาดังกล่าวถึงแม้เปลี่ยนไปใช้อัลกอริทึมเข้ารหัสแบบสตรีม (Stream Cipher) ก็ไม่สามารถแก้ได้ เพราะผลลัพท์ที่ได้จากอัลกอริทึมเข้ารหัสแบบสตรีมจะมีขนาดเท่ากับ plaintext ดังนั้นความยาวของรหัสผ่านยังสามารถดูได้จากความยาวของผลลัพท์จากการเข้ารหัสอยู่ดี
วิธีแก้ปัญหาที่ดีที่สุดคือ เข้ารหัสความยาวของรหัสผ่านไปพร้อมกับตัวรหัสผ่านด้วยอัลกอริทึมเข้ารหัสแบบบล็อค ตัวอย่างเช่น สร้าง plaintext ขึ้นใหม่โดยกำหนดให้ 2 ไบต์แรกเก็บความยาวของรหัสผ่านและไบต์ที่เหลือคือรหัสผ่าน แล้วนำ plaintext ทั้งหมดไป padding แล้วส่งไปเข้ารหัสตามปกติ
ข้อแนะนำในการใช้ SALT
ทั้งวิธีการเข้ารหัส และการใช้ฟังก์ชั่นแฮชมีปัญหาอย่างเดียวกันคือ เมื่อผู้ใช้สองคนใช้รหัสผ่านเดียวกัน ค่าที่ได้จากการเข้ารหัส และค่าแฮชจะเป็นค่าเดียวกัน ซึ่งปัญหานี้สามารถแก้ได้โดย SALT
SALT คือข้อมูลชุดหนึ่งที่สุ่มเพิ่มขึ้นมาเพื่อนำมาต่อกับข้อมูลที่จะนำไปผ่านฟังก์ชั่นแฮช (หรืออัลกอริทึมเข้ารหัส) ดังนั้นถึงแม้จะมีรหัสผ่านเดียวกันแต่มี SALT ต่างกันจะได้ค่าแฮชที่ต่างกัน
นอกจากนี้การใช้ SALT ยังเพิ่มความปลอดภัยอย่างมากเมื่อเผชิญกับการโจมตีด้วย Rainbow Table หรือการโจมตีประเภท Time-Memory Trade-Off (TMTO)
การใช้ SALT ควบคู่กับฟังก์ชั่นแฮชมีขั้นตอนการทำงานดังนี้
- สร้างเลขสุ่มขึ้นมาโดย Cryptographically Secure Pseudorandom Generator
- นำเลขสุ่มที่สร้างขึ้นไปต่อกับรหัสผ่าน
- คำนวณค่าแฮชของค่าที่ได้จากข้อสอง
- เก็บค่าแฮชพร้อมทั้ง SALT ลงฐานข้อมูล
ในขั้นตอนการตรวจสอบสิทธิ์สามารถทำได้ดังนี้
- นำ SALT ของผู้ใช้ที่เก็บไว้มาต่อกับรหัสผ่านที่ผู้ใช้ส่งมา
- คำนวณค่าแฮชที่ได้จากข้อ 1
- เทียบค่าแฮชที่ได้กับค่าแฮชที่อยู่ในฐานข้อมูล ถ้าตรงกันแสดงว่ารหัสผ่านถูกต้อง ถ้าไม่ตรงกันแสดงว่ารหัสผ่านไม่ถูกต้อง
การนำชื่อผู้ใช้มาเป็น SALT ไม่แนะนำให้ทำอย่างยิ่งเพราะชื่อผู้ใช้ไม่ถือเป็นการสุ่ม และถ้ามีการเปลี่ยนชื่อผู้ใช้จะทำให้วิธีนี้ทำงานไม่ถูกต้อง และเครื่องสร้างเลขสุ่มเทียมต้องเป็น Cryptographically Secure Pseudorandom Generator เท่านั้น การใช้เครื่องสร้างเลขสุ่มเทียมทั่วไปถือว่าเสี่ยงมาก