Security
SQL Injection คืออะไร? พูดง่ายๆ มันคือการ "แฮ็ก" โดยการแทรกโค้ด SQL ที่เป็นอันตรายเข้าไปในคำสั่ง SQL ที่เว็บแอปพลิเคชันของเราสร้างขึ้น สมัยผมทำร้านเน็ต เคยเจอเคสเด็กมันใส่โค้ดแปลกๆ ในช่อง username password แล้วเข้าเครื่องแอดมินได้เฉยเลย ตอนนั้นงงมาก เพิ่งมารู้ทีหลังว่ามันคือ SQL Injection นี่แหละ
ทำไมมันถึงสำคัญ? เพราะมันอันตรายมากๆ! คนร้ายสามารถ:
คิดภาพตามนะ ถ้าเว็บขายของออนไลน์โดนแฮ็ก แล้วคนร้ายเปลี่ยนราคาสินค้าทุกชิ้นให้เป็น 1 บาท จะเกิดอะไรขึ้น? หรือถ้าเว็บธนาคารถูกเจาะ แล้วคนร้ายโอนเงินออกจากบัญชีลูกค้า จะเสียหายขนาดไหน?
ลองดูตัวอย่างง่ายๆ สมมติว่าเรามี form login ที่รับ username และ password แล้วเอาไป query ในฐานข้อมูลแบบนี้:
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
// รันคำสั่ง SQL
ถ้าคนร้ายใส่ username เป็น ' OR '1'='1 และ password เป็นอะไรก็ได้ คำสั่ง SQL จะกลายเป็น:
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'อะไรก็ได้'
'1'='1' เป็นจริงเสมอ ดังนั้นคำสั่ง SQL นี้จะเลือกทุก row ในตาราง users ทำให้คนร้ายสามารถ login เข้าสู่ระบบได้โดยไม่ต้องรู้ username และ password ที่ถูกต้อง
นี่เป็นแค่ตัวอย่างง่ายๆ SQL Injection สามารถซับซ้อนกว่านี้ได้เยอะมาก ขึ้นอยู่กับความรู้ความสามารถของคนร้าย และช่องโหว่ของระบบ
SQL Injection มีหลายประเภท แต่หลักๆ จะมี:
In-band SQLi เป็นประเภทที่พบบ่อยที่สุด และง่ายต่อการ exploit ที่สุด
ป้องกันไว้ดีกว่าแก้! นี่คือวิธีป้องกัน SQL Injection ที่ผมใช้มาตลอด:
วิธีนี้คือวิธีที่ดีที่สุดในการป้องกัน SQL Injection Prepared statements จะแยกโค้ด SQL ออกจากข้อมูล ทำให้คนร้ายไม่สามารถแทรกโค้ด SQL ที่เป็นอันตรายเข้าไปได้
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->execute();
// ดึงข้อมูล
สังเกตว่าเราใช้ :username และ :password เป็น placeholder แล้วใช้ bindParam() เพื่อใส่ข้อมูลเข้าไป วิธีนี้จะทำให้ข้อมูลถูก escape โดยอัตโนมัติ ทำให้ SQL Injection ไม่สามารถทำงานได้
ตรวจสอบข้อมูลที่ผู้ใช้ป้อนเข้ามาเสมอ! อย่าเชื่อใจข้อมูลจากภายนอก Input validation ช่วยป้องกัน SQL Injection ได้ในระดับหนึ่ง แต่ไม่สามารถป้องกันได้ทั้งหมด
$username = $_POST['username'];
$password = $_POST['password'];
// ตรวจสอบความยาวของ username และ password
if (strlen($username) < 3 || strlen($username) > 20) {
// แสดงข้อผิดพลาด
}
// ตรวจสอบว่า username และ password มีตัวอักษรที่ไม่ถูกต้องหรือไม่
if (!preg_match('/^[a-zA-Z0-9]+$/', $username) || !preg_match('/^[a-zA-Z0-9]+$/', $password)) {
// แสดงข้อผิดพลาด
}
Input validation ควรทำทั้งฝั่ง client (JavaScript) และฝั่ง server (PHP, Python, etc.)
ให้สิทธิ์การเข้าถึงฐานข้อมูลแก่ผู้ใช้เท่าที่จำเป็นเท่านั้น อย่าให้สิทธิ์ admin แก่ทุกคน
สร้าง user account ที่มีสิทธิ์จำกัดในการเข้าถึงข้อมูล และใช้งาน user account นั้นในการเชื่อมต่อกับฐานข้อมูล
อัปเดตซอฟต์แวร์ที่ใช้ (เช่น PHP, MySQL) ให้เป็นเวอร์ชันล่าสุดเสมอ เวอร์ชันใหม่ๆ มักจะมี patch แก้ไขช่องโหว่ด้านความปลอดภัย
สมัครรับข่าวสารด้านความปลอดภัย เพื่อรับทราบข้อมูลเกี่ยวกับช่องโหว่ใหม่ๆ และวิธีการแก้ไข
| วิธี | ข้อดี | ข้อเสีย | ความยากง่าย |
|---|---|---|---|
| Prepared Statements | ป้องกัน SQL Injection ได้ดีที่สุด | ต้องเขียนโค้ดเพิ่ม | ปานกลาง |
| Input Validation | ป้องกัน SQL Injection ได้ในระดับหนึ่ง | ไม่สามารถป้องกันได้ทั้งหมด | ง่าย |
| Least Privilege | ลดความเสียหายหากโดนแฮ็ก | ต้องจัดการ user account | ปานกลาง |
ดูวิดีโอเพิ่มเติมเกี่ยวกับSQL Injection คืออะไร ป้องกันย:
ไม่! ไม่มีอะไรป้องกันได้ 100% แต่ถ้าทำตามวิธีที่แนะนำ โอกาสที่จะโดนแฮ็กลดลงไปเยอะมาก
ทุกเว็บไซต์ที่ใช้ฐานข้อมูลมีความเสี่ยง แต่เว็บไซต์ที่มีข้อมูลสำคัญ (เช่น ข้อมูลลูกค้า, ข้อมูลทางการเงิน) จะมีความเสี่ยงสูงกว่า
รีบแจ้งผู้เชี่ยวชาญด้านความปลอดภัยทันที! เปลี่ยน password ทุกอย่าง, ตรวจสอบ log files, และ restore ข้อมูลจาก backup (ถ้ามี)
หวังว่าบทความนี้จะเป็นประโยชน์นะ ถ้าอยากอ่านเรื่องอื่นๆ อีก แวะไป SiamCafe Blog ได้เลย มีบทความดีๆ อีกเยอะเลย
อย่าลืม SiamCafe Blog นะครับ!
สมัยผมทำร้านเน็ตฯ ระบบสมาชิกนี่ตัวดีเลย โดน SQL Injection กันง่ายมาก เพราะเขียน query แบบเอาตัวแปรไปแปะๆ ใน string เลย ซึ่งผิด! ให้ใช้ Prepared Statements หรือ Parameterized Queries แทน มันจะแยก data ออกจาก code ทำให้ SQL เข้าใจว่า input เป็นแค่ data ไม่ใช่คำสั่ง
// PHP ตัวอย่างการใช้ Prepared Statements
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$username, $password]);
$user = $stmt->fetch();
เห็นไหม? เราไม่ได้เอา $username กับ $password ไปต่อ string เอง แต่ส่งไปให้ database handle เองเลย ปลอดภัยกว่าเยอะ
ถึงจะใช้ Prepared Statements แล้ว ก็อย่าประมาท! validate input ทุกครั้ง ตรวจสอบชนิดของข้อมูล, ความยาว, รูปแบบ ว่าตรงตามที่เราต้องการหรือเปล่า แล้วก็ sanitize input พวก character พิเศษต่างๆ ที่อาจจะก่อปัญหา
// PHP ตัวอย่างการ validate input
if (strlen($username) > 50) {
die("Username ยาวเกินไป!");
}
// PHP ตัวอย่างการ sanitize input
$username = htmlspecialchars($username); // ป้องกัน XSS ด้วย
สมัยก่อนไม่ค่อย validate กัน โดน inject กันกระจาย พอโดนแล้วต้องมานั่งไล่แก้ data base กันหัวหมุน
ให้ user ใน database มีสิทธิ์เท่าที่จำเป็นเท่านั้น อย่าให้ user ที่ใช้ connect กับ application มีสิทธิ์เป็น root หรือ admin เด็ดขาด ถ้าโดน inject ไป ก็เสียหายบานปลาย
เคยเจอเคส admin ตั้ง password ง่ายๆ แล้วโดน hack เข้าไปแก้ permission user ใน database กลายเป็นว่า hacker เข้าถึงข้อมูลลูกค้าได้หมดเลย
Software และ libraries ที่เราใช้มีช่องโหว่อยู่เรื่อยๆ อัพเดทให้เป็น version ล่าสุดเสมอ จะได้ patch ช่องโหว่เหล่านั้น
สมัยก่อนไม่ค่อยมีใครอัพเดทกัน เพราะกลัวระบบรวน แต่จริงๆ แล้วการไม่อัพเดทนี่แหละคือความเสี่ยงที่ใหญ่กว่า
บอกเลยว่าไม่มีอะไรป้องกันได้ 100% แต่ถ้าทำตาม Best Practices ที่บอกไป ก็ลดความเสี่ยงไปได้เยอะมากๆ ที่สำคัญคือต้องตระหนักถึงความเสี่ยงอยู่เสมอ และคอย update ความรู้ตัวเอง
ORM (Object-Relational Mapping) ช่วยได้ในระดับหนึ่ง เพราะมันจะ generate SQL query ให้เรา แต่ก็ไม่ได้หมายความว่าจะปลอดภัย 100% เรายังต้อง validate input และระวังเรื่อง configuration ของ ORM ด้วย
มีเยอะแยะเลยครับ ทั้งแบบ Open Source และ Commercial ลองหาดูตามความเหมาะสม แต่ tool พวกนี้ก็ไม่ได้ครอบคลุมทุกอย่าง เรายังต้องใช้ความรู้ความเข้าใจของเราในการตรวจสอบด้วย
อันดับแรกคือต้องหยุดระบบทันที! แล้วรีบตรวจสอบ log เพื่อหาว่า hacker เข้ามาทำอะไรบ้าง เปลี่ยน password ทุกอย่าง และกู้ข้อมูลจาก backup ถ้ามี iCafeForex เคยโดนสมัยก่อน Backup สำคัญมาก!
SQL Injection เป็นภัยร้ายที่ต้องระวังให้ดี การป้องกัน SQL Injection ไม่ใช่เรื่องยาก แต่ต้องใส่ใจในรายละเอียด และทำตาม Best Practices ที่แนะนำไป ที่สำคัญคือต้อง update ความรู้ตัวเองอยู่เสมอ เพราะเทคนิคการโจมตีมันก็พัฒนาไปเรื่อยๆ เหมือนกัน เข้าไปอ่านบทความอื่นๆ ได้ที่ SiamCafe Blog