メインコンテンツへ移動

เนื้อหาภาษาไทย / タイ語のコンテンツ

システムガイド 内容確認済み

การใช้ Prepared Statements กับ LIKE Operator

บทความนี้กล่าวถึงความสำคัญของการใช้ Prepared Statements ร่วมกับ `LIKE` operator อย่างระมัดระวังเพื่อป้องกัน SQL Injection เมื่อมีการค้นหาข้อมูลโดยใช้ข้อมูลที่ผู...

การใช้ Prepared Statements กับ LIKE Operator อย่างปลอดภัย

ในบทก่อนหน้า เราได้เรียนรู้เกี่ยวกับ Session Hijacking และวิธีการป้องกัน ในบทนี้ เราจะมาเจาะลึกการใช้งาน Prepared Statements กับ LIKE operator อย่างปลอดภัย ซึ่งเป็นสิ่งสำคัญอย่างยิ่งในการป้องกัน SQL Injection เมื่อมีการค้นหาข้อมูลด้วยเงื่อนไขที่ผู้ใช้ป้อนเข้ามา

ทำไมต้องระวังเมื่อใช้ LIKE กับ Prepared Statements?

LIKE operator ใช้สำหรับค้นหาข้อมูลที่ตรงกับรูปแบบ (pattern) ที่กำหนด โดยมักใช้ร่วมกับ wildcard characters เช่น % (แทนอักขระใดๆ ก็ได้ 0 ตัวขึ้นไป) และ _ (แทนอักขระใดๆ ก็ได้ 1 ตัว) หากเรานำค่าจากผู้ใช้มาใส่ใน pattern ของ LIKE โดยตรง โดยไม่มีการตรวจสอบหรือป้องกัน อาจทำให้เกิดช่องโหว่ SQL Injection ได้

ยกตัวอย่างเช่น หากผู้ใช้ป้อนค่า "test%" แล้วเรานำค่านี้ไปใช้ใน query โดยตรง อาจทำให้ผู้ไม่ประสงค์ดีสามารถใส่ SQL code ที่เป็นอันตรายลงไปใน pattern ได้

การ Escape Wildcard Characters

ขั้นตอนแรกในการใช้งาน LIKE กับ Prepared Statements อย่างปลอดภัย คือการ escape wildcard characters ที่อาจมีอยู่ใน input ของผู้ใช้ เพื่อให้ % และ _ ถูกตีความเป็น literal characters แทนที่จะเป็น wildcard characters

เราสามารถใช้ฟังก์ชัน str_replace() ใน PHP เพื่อ escape wildcard characters ได้ดังนี้:

<?php
function escapeLikeWildcards(string $input): string {
    $escaped = str_replace(['%', '_'], ['\%', '\_'], $input);
    return $escaped;
}

$userInput = $_GET['search']; // สมมติว่ารับค่ามาจาก GET request
$escapedInput = escapeLikeWildcards($userInput);

echo "Escaped input: " . $escapedInput;
?>

ในตัวอย่างนี้ ฟังก์ชัน escapeLikeWildcards() จะทำการแทนที่ % ด้วย \% และ _ ด้วย \_ ใน input string ทำให้ wildcard characters ถูก escape และตีความเป็น literal characters

เหตุผลเชิงออกแบบ: การสร้างฟังก์ชัน escapeLikeWildcards() ช่วยให้โค้ดของเรามีความ reusable และอ่านง่ายขึ้น นอกจากนี้ยังช่วยให้เราสามารถปรับเปลี่ยนวิธีการ escape wildcard characters ได้ง่าย หากจำเป็น

การใช้ bindParam() กับ LIKE

หลังจาก escape wildcard characters แล้ว เราสามารถใช้ bindParam() เพื่อ bind ค่าที่ escape แล้วเข้ากับ Prepared Statement ได้อย่างปลอดภัย

<?php
// สมมติว่ามีการเชื่อมต่อฐานข้อมูล PDO แล้ว ($pdo)

$userInput = $_GET['search'];
$escapedInput = escapeLikeWildcards($userInput);

$stmt = $pdo->prepare("SELECT * FROM products WHERE name LIKE :search");
$stmt->bindParam(':search', '%' . $escapedInput . '%', PDO::PARAM_STR); // เพิ่ม % เพื่อให้ค้นหาแบบ contains
$stmt->execute();

$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

// แสดงผลลัพธ์
foreach ($results as $row) {
    echo $row['name'] . "<br>";
}
?>

ในตัวอย่างนี้ เราได้ทำการ:

  1. Escape wildcard characters ใน $userInput
  2. สร้าง Prepared Statement ที่ใช้ LIKE :search
  3. ใช้ bindParam() เพื่อ bind ค่า '%' . $escapedInput . '%' เข้ากับ placeholder :search
  4. เพิ่ม % ทั้งด้านหน้าและด้านหลังของ $escapedInput เพื่อให้ค้นหาข้อมูลที่มี $escapedInput เป็นส่วนหนึ่งของชื่อ (contains)
  5. Execute query และดึงข้อมูล

เหตุผลเชิงออกแบบ: การใช้ bindParam() ช่วยป้องกัน SQL Injection โดยการแยก query structure ออกจาก data ทำให้ database engine สามารถ compile query ได้ก่อนที่จะรับ data จากผู้ใช้ ทำให้ไม่สามารถแทรก SQL code ที่เป็นอันตรายเข้าไปใน query ได้

ข้อควรระวัง: การใส่ % ก่อนและหลัง $escapedInput ใน bindParam() เป็นสิ่งที่จำเป็นหากเราต้องการค้นหาข้อมูลที่ *มี* ค่าที่ผู้ใช้ป้อนเข้ามาเป็นส่วนหนึ่งของข้อมูล หากเราต้องการค้นหาข้อมูลที่ *เริ่มต้นด้วย* ค่าที่ผู้ใช้ป้อนเข้ามา เราสามารถใส่ % ไว้แค่ด้านหลังของ $escapedInput เท่านั้น

ตัวอย่างการใช้งาน LIKE แบบต่างๆ

ต่อไปนี้เป็นตัวอย่างการใช้งาน LIKE แบบต่างๆ:

  • ค้นหาข้อมูลที่เริ่มต้นด้วยคำที่ผู้ใช้ป้อน:
  • <?php
    $stmt = $pdo->prepare("SELECT * FROM products WHERE name LIKE :search");
    $stmt->bindParam(':search', $escapedInput . '%', PDO::PARAM_STR);
    $stmt->execute();
    ?>
    
  • ค้นหาข้อมูลที่ลงท้ายด้วยคำที่ผู้ใช้ป้อน:
  • <?php
    $stmt = $pdo->prepare("SELECT * FROM products WHERE name LIKE :search");
    $stmt->bindParam(':search', '%' . $escapedInput, PDO::PARAM_STR);
    $stmt->execute();
    ?>
    
  • ค้นหาข้อมูลที่ตรงกับคำที่ผู้ใช้ป้อน (exact match): (ไม่แนะนำให้ใช้ LIKE สำหรับ exact match ควรใช้ `=` แทน)
  • <?php
    // ไม่แนะนำ! ควรใช้ WHERE name = :search แทน
    $stmt = $pdo->prepare("SELECT * FROM products WHERE name LIKE :search");
    $stmt->bindParam(':search', $escapedInput, PDO::PARAM_STR);
    $stmt->execute();
    ?>
    

แนวปฏิบัติที่ดี:

  • ตรวจสอบ input ของผู้ใช้เสมอ: ก่อนที่จะนำ input ของผู้ใช้มาใช้ใน query ใดๆ ควรตรวจสอบ input นั้นก่อนเสมอ เพื่อให้แน่ใจว่าเป็นไปตามรูปแบบที่คาดหวัง
  • ใช้ Prepared Statements เสมอ: หลีกเลี่ยงการสร้าง query โดยการต่อ string โดยตรง เพราะอาจทำให้เกิดช่องโหว่ SQL Injection ได้
  • Escape wildcard characters: เมื่อใช้ LIKE operator ให้ escape wildcard characters เสมอ
  • ใช้ bindParam(): ใช้ bindParam() เพื่อ bind ค่าเข้ากับ Prepared Statement อย่างปลอดภัย
  • ใช้ `=` แทน LIKE สำหรับ exact match: หากต้องการค้นหาข้อมูลที่ตรงกับค่าที่กำหนดอย่างแม่นยำ ควรใช้ `=` operator แทน LIKE operator

สรุป

การใช้ Prepared Statements กับ LIKE operator อย่างปลอดภัย เป็นสิ่งสำคัญในการป้องกัน SQL Injection เมื่อมีการค้นหาข้อมูลด้วยเงื่อนไขที่ผู้ใช้ป้อนเข้ามา โดยเราต้องทำการ escape wildcard characters และใช้ bindParam() เพื่อ bind ค่าเข้ากับ Prepared Statement อย่างถูกต้อง นอกจากนี้ เราควรตรวจสอบ input ของผู้ใช้เสมอ และใช้ `=` operator แทน LIKE operator หากต้องการค้นหาข้อมูลที่ตรงกับค่าที่กำหนดอย่างแม่นยำ

ในบทถัดไป เราจะเรียนรู้เกี่ยวกับการใช้ PDO กับ UNION statement ซึ่งเป็นอีกหนึ่งเทคนิคที่สำคัญในการจัดการฐานข้อมูล

Office.in.th Custom Service

この構成をもとにシステムを開発・カスタマイズしたいですか?

Office.in.th は、エンタープライズ Web アプリケーション、API 連携、官民の業務管理システムの設計・開発を承り、長期的なサポートも提供します。

ソフトウェア開発サービスを見る