SQLi หรือ SQL injection

SQLi หรือ SQL injection

SQL Injection (SQLi) คือหนึ่งในช่องโหว่ด้านความปลอดภัยที่อันตรายและพบบ่อยที่สุดในการพัฒนาเว็บแอปพลิเคชันครับการโจมตีเว็บด้วย SQLi หรือ SQL injection เป็นการแฝงข้อมูลไปกับการนำเข้าข้อมูล ความอันตารายคือสามารถเข้าถึงข้อมูลได้ทันทีหรือ ล็อกอินเข้าระบบ

SQL Injection คืออะไร?

SQL Injection คือการที่แฮกเกอร์แอบใส่ (Inject) "คำสั่ง SQL อันตราย" ลงไปในช่องกรอกข้อมูล (เช่น ช่องค้นหา, ช่อง Login) เพื่อหลอกให้ฐานข้อมูลทำงานตามที่แฮกเกอร์ต้องการแทนที่จะทำงานตามปกติ ตัวอย่างเช่น: สมมติคุณมีโค้ดตรวจสอบการ Login แบบธรรมดา (ที่ไม่ได้ป้องกัน) ดังนี้:

SELECT * FROM users WHERE username = 'admin' AND password = ' ' OR 1=1 -- '

แฮกเกอร์อาจจะพิมพ์รหัสผ่านเป็น ' OR 1=1 -- ซึ่งทำให้ระบบมองว่าเงื่อนไข 1=1 เป็นจริงเสมอ (True) และเครื่องหมาย -- จะคอมเมนต์คำสั่งที่เหลือทิ้งไป ทำให้แฮกเกอร์สามารถล็อกอินเข้าสู่ระบบได้โดยไม่ต้องรู้รหัสผ่านจริงๆ หรือเลวร้ายกว่านั้นคืออาจจะสั่งลบฐานข้อมูล (DROP TABLE) ได้เลย

ป้องกันด้วยการ prepare (Prepared Statements) ทำยังไง?

การทำ Prepared Statements (หรือบางครั้งเรียกว่า Parameterized Queries) คือวิธีป้องกัน SQL Injection หลักการทำงานของมันคือ "การแยกโครงสร้างคำสั่ง SQL ออกจากข้อมูล (Data) อย่างเด็ดขาด" กระบวนการทำงานมี 2 ขั้นตอน:

Prepare (เตรียมคำสั่ง): แอปพลิเคชันจะส่งโครงสร้างคำสั่ง SQL ไปให้ฐานข้อมูลก่อน โดยเว้นช่องว่างไว้ให้ใส่ข้อมูลทีหลัง (มักจะใช้สัญลักษณ์ ? หรือ :name เป็นตัวแทน) เช่น SELECT * FROM users WHERE username = ? AND password = ?

Execute (ส่งข้อมูลและรัน): แอปพลิเคชันจะส่ง "ข้อมูล" ตามไปทีหลัง ฐานข้อมูลจะนำข้อมูลนี้ไปใส่ในช่องว่างที่เตรียมไว้

ป้องกันได้เพราะฐานข้อมูลถูกสั่งให้มองข้อมูลที่ส่งมาในขั้น Execute เป็น "ข้อความธรรมดา (Literal Data)" เท่านั้น ไม่ใช่คำสั่ง (Executable Code) ดังนั้น ต่อให้แฮกเกอร์จะส่งคำสั่ง ' OR 1=1 -- เข้ามา ฐานข้อมูลก็จะมองหาผู้ใช้ที่มีรหัสผ่านเป็นคำว่า ' OR 1=1 -- ตรงๆ ซึ่งหาไม่เจอแน่นอน คำสั่งอันตรายจึงไม่ถูกทำงานครับ

ทำในส่วนไหนของระบบ?

การทำ Prepared Statements จะทำใน ฝั่ง Backend (Server-side)มันคือส่วนที่เขียนโค้ดเชื่อมต่อและส่งคำสั่งโต้ตอบกับฐานข้อมูล (Database) ก่อนที่โค้ดฝั่ง Backend ของคุณจะส่ง Query ไปยัง Database Engine (เช่น MySQL, PostgreSQL, SQL Server) คุณจะต้องเขียนระบุให้มันใช้ฟังก์ชันแบบ Prepare แทนการนำ String มาต่อกัน (String Concatenation)

มักใช้ในภาษาอะไรได้บ้าง PHP: ใช้ผ่าน PDO (PHP Data Objects) หรือ MySQLi

// ตัวอย่าง PDO ใน PHP $stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email'); $stmt->execute(['email' => $userInputEmail]);

Node.js (JavaScript/TypeScript): ใช้ผ่านไลบรารีอย่าง pg (PostgreSQL) หรือ mysql2 (MySQL)

// ตัวอย่าง mysql2 ใน Node.js connection.execute( 'SELECT * FROM users WHERE email = ?', [userInputEmail], function(err, results, fields) { ... } );

Python: ใช้ผ่าน sqlite3, psycopg2 หรือ ORM อย่าง SQLAlchemy

# ตัวอย่าง sqlite3 ใน Python cursor.execute("SELECT * FROM users WHERE email = ?", (userInputEmail,))

(หมายเหตุ: หากคุณใช้ระบบ ORM เช่น Prisma, TypeORM, Entity Framework, Django ORM หรือ Eloquent ของ Laravel ระบบเหล่านี้มักจะทำ Prepared Statements ให้คุณโดยอัตโนมัติอยู่แล้ว)