Skip to main content

เนื้อหาภาษาไทย / Thai content

System guide Content reviewed

Security Best Practices: Preventing SQL Injection

บทความนี้เน้นถึงอันตรายของ SQL Injection ซึ่งเกิดจากการแทรกโค้ด SQL อันตรายลงในคำสั่ง SQL ของแอปพลิเคชัน โดยเฉพาะอย่างยิ่งเมื่อใช้ข้อมูลนำเข้าจากผู้ใช้โดยไม่ได้...

Security Best Practices: Preventing SQL Injection

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

SQL Injection คืออะไร?

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

ลองนึกภาพว่าคุณมีฟอร์มสำหรับค้นหาผู้ใช้ตามชื่อผู้ใช้ (username) ในฐานข้อมูล คำสั่ง SQL ที่ใช้ค้นหาอาจมีลักษณะดังนี้:

SELECT * FROM users WHERE username = '$username';

หากผู้ใช้ป้อนข้อมูลที่คาดหวัง เช่น john คำสั่ง SQL จะเป็น:

SELECT * FROM users WHERE username = 'john';

ซึ่งจะทำงานตามที่คาดหวัง แต่ถ้าผู้ใช้ป้อนข้อมูลที่เป็นอันตราย เช่น ' OR '1'='1 คำสั่ง SQL จะกลายเป็น:

SELECT * FROM users WHERE username = '' OR '1'='1';

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

Prepared Statements และ Parameterized Queries: เกราะป้องกัน SQL Injection

วิธีที่ดีที่สุดในการป้องกัน SQL Injection คือการใช้ Prepared Statements หรือ Parameterized Queries ซึ่งเป็นคุณสมบัติที่ฐานข้อมูลส่วนใหญ่รองรับ

หลักการทำงาน: Prepared Statements แยกกระบวนการสร้างคำสั่ง SQL ออกเป็นสองขั้นตอน:

  1. Preparation: สร้างโครงสร้างของคำสั่ง SQL โดยมีตัวยึดตำแหน่ง (placeholders) สำหรับค่าที่จะใส่ในภายหลัง ตัวอย่างเช่น: SELECT * FROM users WHERE username = ?
  2. Execution: ส่งค่าที่ต้องการให้กับตัวยึดตำแหน่ง โดยฐานข้อมูลจะจัดการกับการ Escape และการแปลงข้อมูลที่จำเป็น เพื่อให้แน่ใจว่าค่าเหล่านั้นจะไม่ถูกตีความว่าเป็นส่วนหนึ่งของคำสั่ง SQL

ข้อดีของการใช้ Prepared Statements:

  • ป้องกัน SQL Injection: เนื่องจากค่าถูกส่งแยกจากคำสั่ง SQL ทำให้ฐานข้อมูลสามารถจัดการกับการ Escape และการแปลงข้อมูลได้อย่างปลอดภัย
  • Performance Improvement: Prepared Statements สามารถถูก Compile และ Optimize ได้เพียงครั้งเดียว จากนั้นสามารถนำกลับมาใช้ใหม่ได้หลายครั้ง ซึ่งช่วยลดภาระของฐานข้อมูล
  • Code Readability: Code ที่ใช้ Prepared Statements มักจะอ่านง่ายกว่า เนื่องจากมีการแยกส่วนของคำสั่ง SQL และข้อมูลออกจากกัน

ตัวอย่างการใช้ Prepared Statements ใน PHP (PDO):

try {
  $pdo = new PDO("mysql:host=localhost;dbname=mydb", "username", "password");
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  $username = $_POST['username'];

  $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
  $stmt->bindParam(':username', $username);
  $stmt->execute();

  $user = $stmt->fetch(PDO::FETCH_ASSOC);

  if ($user) {
    // ผู้ใช้ถูกพบ
    echo "Welcome, " . $user['username'];
  } else {
    // ไม่พบผู้ใช้
    echo "Invalid username";
  }

} catch(PDOException $e) {
  echo "Connection failed: " . $e->getMessage();
}

ในตัวอย่างนี้ เราใช้ PDO (PHP Data Objects) ซึ่งเป็นส่วนขยายของ PHP ที่ช่วยให้คุณเข้าถึงฐานข้อมูลต่างๆ ได้อย่างง่ายดาย

  • $pdo->prepare(): เตรียมคำสั่ง SQL โดยใช้ตัวยึดตำแหน่ง :username
  • $stmt->bindParam(): ผูกค่าของ $username กับตัวยึดตำแหน่ง :username
  • $stmt->execute(): รันคำสั่ง SQL

ข้อควรจำ:

  • ควรใช้ Prepared Statements กับทุกคำสั่ง SQL ที่มีการรับข้อมูลจากผู้ใช้
  • ตรวจสอบให้แน่ใจว่าคุณใช้ไลบรารีฐานข้อมูลที่รองรับ Prepared Statements (เช่น PDO หรือ mysqli)

Escaping User Input: ทางเลือกสุดท้าย (แต่ไม่แนะนำ)

แม้ว่า Prepared Statements จะเป็นวิธีที่ดีที่สุดในการป้องกัน SQL Injection แต่ในบางสถานการณ์ คุณอาจจำเป็นต้องใช้การ Escape ข้อมูลที่ผู้ใช้ป้อนเข้ามา

Escaping คือกระบวนการแปลงอักขระพิเศษในข้อมูลที่ผู้ใช้ป้อนเข้ามาให้เป็นรูปแบบที่ปลอดภัย เพื่อให้ฐานข้อมูลไม่ตีความอักขระเหล่านั้นว่าเป็นส่วนหนึ่งของคำสั่ง SQL

ตัวอย่างการ Escape ข้อมูลใน PHP (mysqli):

$conn = mysqli_connect("localhost", "username", "password", "mydb");

$username = mysqli_real_escape_string($conn, $_POST['username']);

$sql = "SELECT * FROM users WHERE username = '" . $username . "'";

$result = mysqli_query($conn, $sql);

ในตัวอย่างนี้ เราใช้ฟังก์ชัน mysqli_real_escape_string() เพื่อ Escape ข้อมูลในตัวแปร $username

ข้อเสียของการใช้ Escaping:

  • Error-Prone: คุณต้องจำให้ได้ว่าจะต้อง Escape ข้อมูลทุกครั้งที่มีการใช้ข้อมูลที่ผู้ใช้ป้อนเข้ามาในคำสั่ง SQL หากลืม Escape ข้อมูลเพียงครั้งเดียว ก็อาจทำให้เกิดช่องโหว่ SQL Injection ได้
  • Database-Specific: ฟังก์ชัน Escape มักจะแตกต่างกันไปในแต่ละฐานข้อมูล ซึ่งหมายความว่าคุณต้องใช้ฟังก์ชัน Escape ที่ถูกต้องสำหรับฐานข้อมูลที่คุณกำลังใช้งาน
  • Less Efficient: Escaping อาจมีประสิทธิภาพน้อยกว่า Prepared Statements เนื่องจากฐานข้อมูลต้องทำการ Escape ข้อมูลทุกครั้งที่มีการรันคำสั่ง SQL

สรุป: การใช้ Prepared Statements เป็นวิธีที่ดีที่สุดในการป้องกัน SQL Injection หากไม่สามารถใช้ Prepared Statements ได้ ให้ใช้ Escaping อย่างระมัดระวัง และตรวจสอบให้แน่ใจว่าคุณใช้ฟังก์ชัน Escape ที่ถูกต้องสำหรับฐานข้อมูลที่คุณกำลังใช้งาน

สรุป

SQL Injection เป็นช่องโหว่ที่ร้ายแรงที่สามารถนำไปสู่การสูญเสียข้อมูลหรือการควบคุมระบบ การป้องกัน SQL Injection เป็นสิ่งสำคัญอย่างยิ่งสำหรับทุกแอปพลิเคชัน PHP

แนวทางปฏิบัติที่ดีที่สุด:

  • ใช้ Prepared Statements หรือ Parameterized Queries กับทุกคำสั่ง SQL ที่มีการรับข้อมูลจากผู้ใช้
  • หลีกเลี่ยงการใช้ Escaping หากเป็นไปได้
  • ตรวจสอบและกรองข้อมูลนำเข้า อย่างเข้มงวด
  • ใช้สิทธิ์ที่จำเป็นขั้นต่ำ (Least Privilege) สำหรับบัญชีฐานข้อมูล
  • ติดตามและตรวจสอบ การเข้าถึงฐานข้อมูลอย่างสม่ำเสมอ

ในบทความถัดไป เราจะพูดถึงช่องโหว่อีกประเภทที่พบบ่อย นั่นคือ Cross-Site Scripting (XSS) และวิธีการป้องกัน

Office.in.th Custom Service

Want to build or adapt a system from this structure?

Office.in.th designs and develops enterprise web applications, API integrations, and public- and private-sector management systems, with long-term support.

See our software development service