> For the complete documentation index, see [llms.txt](https://www.saladpuk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.saladpuk.com/basic/security101/secure-password.md).

# การเก็บรหัสผ่านที่ถูกต้อง

ในบทความนี้เราจะมาดูกันว่า การเก็บความลับไว้ในฐานข้อมูลนั้น **ขั้นต่ำ** ที่เรียกว่าปลอดภัยจริงๆมันเป็นยังไง ซึ่งในบทความนี้จะไม่ได้ลงรายละเอียดว่าต้องทำยังไงบ้าง แต่จะให้เข้าใจแนวคิดพื้นฐานในการเพิ่มความปลอดภัยให้กับระบบนะฮ๊าฟ

{% hint style="info" %}
**แนะนำให้อ่าน**\
บทความนี้เป็นส่วนหนึ่งของคอร์ส [👦 Security พื้นฐาน](https://saladpuk.gitbook.io/learn/basic/security101) ถ้าเพื่อนๆสนใจอยากรู้หลักในการรักษาความปลอดภัยตั้งแต่เริ่มต้นเลย ก็กดอ่านที่ตัวสีฟ้าๆได้เลยนะ
{% endhint %}

## 🦉 นิทานเรื่องที่สอง

เว็บไซต์ **เฟสปาล์ม** ได้เปิดตัวบริการ Social Media ที่สั่นสะท้านวงการ ทำให้มีคนนับล้านๆคนเข้าไปใช้บริการอย่างล้นหลา จนมียอดผู้ใช้ทะลุหลัก 1,000 ล้านคนภายในเวลาไม่นาน จนกระทั่งวันหนึ่งก็มีข่าวช๊อกโลก เพราะมีคนจับได้ว่าเฟสปาล์มได้ทำการขายข้อมูลผู้ใช้ให้กับบริษัทต่างๆ เลยทำให้ Hacker ทั่วโลกโกรธเกรี้ยวบริษัทเฟสปาล์มเป็นอันมาก และหนึ่งในบรรดา Hacker ก็เจาะเข้าระบบฐานข้อมูล ดึงข้อมูลผู้ใช้ออกมาได้ส่วนนึง ทำให้มีผู้ใช้หลายล้านรายที่ตกเป็นเหยื่อ เพราะถูกล่วงรู้ รหัสผ่าน และแม้กระทั่งข้อมูลบัตรเครดิตนั่นเอง

ดังนั้นบริษัทเฟสปาล์มเลยต้องมาวางแผนรับมือไม่ให้เกิดปัญหาที่ว่ามานี้อีก โดยสิ่งที่แรกเอามาดูก็คือ **ข้อมูลผู้ใช้ที่อยู่ในฐานข้อมูล** มันเป็นประมาณนี้

| Id | Username | Password |
| -- | -------- | -------- |
| 1  | saladpuk | 1234     |
| 2  | thaksin  | homesick |
| 3  | prayut   | 1234     |

เจ้าหน้าที่รักษาความปลอดภัยที่ชื่อ **ยิน** เห็นแล้วได้ถึงกับตกใจแล้วพูดออกมาว่า

### 🔥 ห้ามเก็บความลับไว้โดยไม่เข้ารหัสนะเฟร้ย !!

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

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

แม้ **วอดก้า** จะหงุดหงิดได้แต่คิดในใจว่า "ทำไมเอ็งไม่ไปแก้ให้มันเจาะไม่ได้แทนฟระ?" แต่เขาก็ไม่ได้พูดออกมา ได้แต่ก้มหน้าเพิ่มให้ระบบต้องทำการเข้ารหัสตัว password ก่อนที่จะเอาไปเก็บลงฐานข้อมูล โดยใช้ **DES** ในการเข้ารหัส ซึ่งทำให้ฐานข้อมูลเป็นแบบนี้ (ผลลัพท์เป็นแบบสมมุตินะ)

| Id | Username | Password       |
| -- | -------- | -------------- |
| 1  | saladpuk | A1B2C3D4       |
| 2  | thaksin  | CF67D00569ACC1 |
| 3  | prayut   | A1B2C3D4       |

**ยิน** มองข้อมูลในฐานข้อมูลตาถลน พร้อมกับตะโกนบอก **วอดก้า** ไปว่า

### 🔥 การเข้ารหัสห้ามทำย้อนกลับได้นะเฟร้ย !!

**วอดก้า** งง เป็นไก่ตาแตกเพราะไม่รู้ว่าจะต้องเข้ารหัสยังไงดี เลยทำให้ **เบลม็อท** เข้ามาช่วยอธิบายให้ฟังเป็นข้อๆว่า **Data Encryption Standard (DES)** ที่ **วอดก้า** ใช้ในการเข้ารหัส มันเป็นรุ่นสมัยก่อนที่เขาไม่ใช้กันแล้ว (56-bits key) เพราะมันตั้งแต่ 1999 มันใช้เวลาแค่ 22 ชั่วโมงนิดๆก็สามารถถอดรหัสกลับมาได้แล้วยังไงล่ะ ดังนั้น**จงเลือก algorithm ที่เหมาะสม**กับมันด้วย ไม่ใช่ตะบี้ตะบันเจอใน Stackoverflow ตัวไหนก็จับมายัดใส่เลย ดังนั้นจงไปศึกษาเพิ่มซะ

### 🔥 ห้ามให้คนอื่นเดาได้ว่ารหัสผ่านแต่ละคนสั้นยาวต่างกัน

**เบลม็อท** ชี้ไปที่รหัสผ่านของเจ้า **saladpuk** กับ **thaksin** แล้วพูดว่า ดูปุ๊ปก็พอจะเดาได้ว่ารหัสผ่านของ saladpuk น่าจะสั้นกว่าของ thaksin ดังนั้นถ้าเขารู้รหัสผ่านของ thaksin เขาก็จะรู้แนวทางในการใส่รหัสผ่านของคนอื่น ที่สั้นหรือยาวกว่าของ thaksin นั่นเอง พูดจบ เบลม็อท ก็เปิดบทความของ **สลักผัก** ขึ้นมาให้อ่านเรื่องการใช้ **HASH** เพื่อแปลงข้อความให้มันมีความยาวเท่ากันเสมอ (ถ้าลืมไปแล้วหรืออยากทบทวนก็กดไปอ่านจากตรงนี้ซะ [การใช้ HASH function](https://saladpuk.gitbook.io/learn/basic/security101#undefined-3))

### 🔥 รหัสผ่านแม้ว่ามันจะเป็นอันเดียวกัน ก็ต้องห้ามให้มันเก็บเป็นค่าเดียวกัน

**เบลม็อท** ชี้ให้เห็นรหัสผ่านของเจ้า **saladpuk** กับ **prayut** ว่าผลลัพท์มันได้เป็นค่าเดียวกันเลย เพราะถ้าเก็บเป็นแบบนี้ เมื่อมีคนถอดรหัสของใครซักคนได้ เขาก็จะรู้รหัสผ่านของคนอื่นๆที่ใช้รหัสแบบเดียวกันทันทีเลยอะดิ ดังนั้นถ้าต้องการให้ **ความลับที่เป็นค่าเดียวกัน แต่ได้ผลลัพท์ต่างกัน** เราก็สามารถใส่ของมั่วๆเข้าไปในความลับนั้นก็ได้ โดยเราเรียกมันว่า **Salt** หรือ **Nonce** (number used only once) นั่นเอง

#### **Salt**

เป็นการ**สุ่มอะไรมั่วๆซักอย่างเข้าไปต่อกับสิ่งที่เราต้องการให้เป็นความลับ** เช่น รหัสผ่านของ saladpuk คือ 1234 เราก็อาจจะสร้าง salt ออกมาเป็น su!sC\* แล้วเอามันไปต่อท้ายหรือไว้ก่อนหน้าก็ได้เลือกเอาซักอย่าง เราก็จะได้ผลลัพท์ออกมาเป็น 1234su!sC\* (ในตัวอย่างคือเอาไปต่อท้าย) ซึ่งผู้ใช้แต่ละคนก็จะต้องมี salt เป็นคนละตัวกันด้วยนะ ดังนั้น รหัสผ้านของ prayut คือ 1234 เราก็จะสร้าง salt ออกมาอีกตัวสมมุติว่าเป็น A#$563d เราก็เอามันมาต่อท้ายก็จะออกมาเป็น 1234A#$563d ดังนั้นพอเอาค่าทั้ง 2 ตัวนี้มีผ่านการ HASH เราก็จะได้ผลลัพท์ที่ไม่เหมือนกันยังไงล่ะ ตามรูปเลย

| Id | Username | Password                         | Salt    |
| -- | -------- | -------------------------------- | ------- |
| 1  | saladpuk | fd4438f5b856bb685004b84221ba794b | su!sC\* |
| 2  | thaksin  | f679b30fde31dff10304dc357300c52b | $%Acdes |
| 3  | prayut   | 3d54cf99f817a21cd9fd2b7218e58fec | A#$563d |

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

### 🔥 การเข้ารหัสควรทำให้มันเสียเวลาในการถอดรหัส

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

#### **Pepper**

หลักการเหมือนกับ salt เลยคือสุ่มของมั่วๆขึ้นมาซักตัว แต่จะ**สุ่มแค่ 1 ตัวอักษร** อาจจะเป็นตัวเล็กหรือตัวใหญ่ก็ได้ เพื่อเอาไปต่อกับความลับของเราให้มันยาวขึ้น เวลาที่เอาไป HASH มันจะได้ผลลัพท์ออกมาไม่เหมือนเพื่อนนั่นแต่ แต่จะต่างกันคือ **มันจะไม่เก็บค่า papper ไว้ที่ไหนอีกเลย** ดังนั้นเวลาที่เราจะตรวจสอบว่าผู้ใช้ ใส่รหัสผ่านถูกหรือเปล่า ระบบจะต้องเสียเวลาในการไปสุ่มตั้ง a-z และ A-Z ซึ่งถ้ามีผลลัพท์ไหนตรงกับรหัสผ่านที่เก็บไว้ ก็แสดงว่ารหัสผ่านที่ส่งเข้ามาถูกต้องนั่นเอง

{% hint style="info" %}
**Pepper**\
หน้าที่หลักของมันจริงๆคือ **ทำให้คนที่จะมาล้วงความลับจะต้องเสียเวลาในการถอดรหัสเพิ่มขึ้นอีกหลายเท่าตัว**นั้นเอง เพราะแม้กระทั่งระบบก็ยังไม่รู้เลยว่าเจ้า pepper ของผู้ใช้คนนั้นๆคืออะไรนั่นเอง
{% endhint %}

### 🔥 กระบวนการทั้งหมดไม่ควรทำบท disk

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

### 🔥 อย่าเขียนการเข้า-ถอดรหัสเอง !!

**ยิน** ได้กล่าวทิ้งท้ายไว้ พร้อมกับบอกว่า เอ็งจะมั่นใจได้ยังไงว่าของที่เขียนเองมันปลอดภัย ดังนั้นจงไปหา library ที่ใช้ในการจัดการเรื่องนี้โดยเฉพาะจะดีกว่า เพราะส่วนใหญ่เขาจะมีการตรวจสอบอยู่ตลอดเวลา และเมื่อไหร่ที่มีอัพเดทว่าตัวนี้ไม่เหมาะสมแล้ว หรืออะไรก็ตาม ส่วนใหญ่เขาก็จะอัพเดท library เพื่ออุดรูรั่วเหล่านั้น ทำให้ระบบของเราได้รับผลพลอยได้ไปด้วยนั่นเอง

## 🤔 ต้องทำขนาดนี้ด้วยเหรอ ?

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

### 🔥 Rainbow Table

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

### 🔥 Dictionary Attack

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

### 🔥 Bruteforce Attack

เป็นการพยายามหาคำตอบโดยแทยที่ทุกความเป็นไปได้ลงไป เช่น แทนค่าตั้งแต่ aaaaaaaa\~ZZZZZZZZZ ไรงี้ เพื่อให้ฟลุ๊คแล้วเจอผลลัพท์ที่ตรงกับ HASH ที่เก็บไว้นั่นเอง ซึ่งปัจจุบันตัว **PIN** ก็พึ่งเป็นข่าวว่าโดนโจมตีโดยใช้เจ้าตัวนี้อยู่ เพราะมันเป็นแค่ตัวเลขไม่เกิน 8 หลักไรงี้ไง

### 🔥 Computing Power

เมื่อหลายปีก่อน เครื่องถอดรหัสสามารถถอด HASH ได้ราวๆ 1,000,000,000 ล้านตัวต่อ 1 วินาที ดังนั้นไม่น่าแปลกใจเลยใช่ไหมว่าทำไมเราต้องทำให้รหัสผ่านมันต้องใช้เวลาให้ถอดรหัสนานที่สุดเท่าที่เป็นไปได้

## 🎯 บทสรุป

การเก็บรหัสผ่านไว้ในฐานข้อมูลจริงๆมีอีกหลายเรื่องที่อยากจะเล่าให้ฟัง ดังนั้นในบทความหน้าเดี๋ยวเรามาลองดูกันว่า แค่เรื่องการ **Login** เข้าสู่ระบบธรรมดาๆที่พบได้ทั่วไป เชื่อไหมว่าเบื้องหลังจริงๆมันไม่ได้ง่ายแบบนั้นนะถ้าเราต้องเอาเรื่อง security เข้ามาใช้ด้วย

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

* ห้ามเก็บความลับเป็น plain text
* แม้กระทั่งคนภายในของเราเองก็ต้องห้ามรู้รหัสลับต่างๆที่เก็บไว้ในฐานข้อมูล
* การถอดรหัสควรจะต้องใช้เวลาในการถอดรหัสนานที่สุดเท่าที่จะทำได้
* รหัสผ่านแม้จะเป็นรหัสเดียวกันก็ต้องเก็บลงในฐานข้อมูลเป็นคนละตัวกัน
* ห้ามให้ใครเดาได้ว่ารหัสผ่านแต่ละคนยาวสั้นต่างกัน
* การเข้ารหัสถอดรหัสต่างๆควรทำใน Memory ห้ามมาทำไว้บน disk
* ให้ใช้ Security Library ที่สากลเขาใช้ ดีกว่าเขียนเองเสมอ
