การป้องกัน SQL Injection ใน PHP

SQL Injection ใน PHP หรือ การปนคำสั่ง SQL ซ้อนเข้าไปในข้อมูลของตัวแปร ที่รับข้อมูลจาก Input ภายนอก เช่น จากกรอก FORM ตัวอย่างเช่น

mysql_query("SELECT * FROM table WHERE name='" . $unsafeVariable . "'");

// จะเกิดอะไรขึ้น ถ้ามีคนกรอกฟอร์มแล้วเรารับข้อมูลเข้ามาในตัวแปร 
$unsafeVariable = $_GET['name']; 

// โดยที่ในฟิล์ด "name" มีผู้ไม่ประสงค์ดีกรอกว่า "hacker'; DELETE FROM table;'";

// หรือ เมื่อ PHP แปลแล้วจะได้
mysql_query("SELECT * FROM table WHERE name='hacker'; DELETE FROM table;''");

เพราะฉะนั้น เขามีกฏอยู่ข้อหนึ่ง สำหรับการรับข้อมูลจาก FORM คือ

อย่าได้เชื่อข้อมูลจากการกรอกของ User โดยเด็ดขาด!!

(จริงๆ รวมทั้งการแป่ะมากับ Query string ด้วย)


แล้วเราจะป้องกันได้อย่างไร?

โดยปกติแล้ว PHP Framework ทุกเจ้ารวมทั้ง Library ทุกเจ้าจะมีแนวทางป้องกัน SQL Injection โดยที่ให้เราปล่อยให้ Framework หรือ Library เหล่านั้นเป็นคนจัดการให้ เช่น

  •  PDO
    $preparedStatement = $db->prepare('SELECT * FROM table WHERE name=:value');
    $preparedStatement->execute(array(':value' => $unsafeValue));
    $rows = $preparedStatement->fetchAll(); 
    
  • Zend Framework
    $db     = Zend_Db::factory( ...options... );
    $select = $db->select()
                 ->from('table')
                 ->where('name = ?', $unsafeValue);
    $rows   = $db->fetchAll($select);
    

  • เขียนป้องกันเอง
    $unsafeValue = stripslashes($unsafeValue);
    $unsafeValue = addslashes($unsafeValue);
    $sql = "SELECT * FROM table WHERE name=\"{$unsafeValue}\" ";
    			
    // SQL ของเราหลังจากแปลแล้วก็จะได้
    SELECT * FROM table WHERE name="hacker'; DELETE FROM table;'"
    			
    // หรือ ถ้าเขาใส่ double quote แทน ก็จะได้
    SELECT * FROM table WHERE name="hacker\"; DELETE FROM table;\""