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

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

สาเหตุของ SQL Injection

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

แนวทางในการป้องกัน SQL Injection

วิธีการป้องกัน SQL Injection นั้นประกอบไปด้วย 3 วิธี ซึ่งผู้พัฒนาระบบจะเลือกใช้วิธีใดวิธีหนึ่ง หรือใช้หลายวิธีในการป้องกัน (Defense in depth) ก็ได้เช่นกันเพื่อความปลอดภัยที่มากขึ้นของเว็บแอปพลิเคชัน โดยวิธีป้องกัน SQL Injection นั้นประกอบไปด้วย

1. Prepared Statements

Prepared Statement  หรืออีกชื่อหนึ่งคือ Parameterised Query เป็นหนึ่งในวิธีการที่ได้รับความนิยมอย่างมากในการป้องกัน SQL Injection เนื่องด้วยความง่ายในการใช้งานและเกือบทุกภาษาที่ใช้ในการเขียนเว็บแอปพลิเคชันในปัจจุบันมี library ให้นักพัฒนาสามารถเรียกใช้งานได้อย่างสะดวก

ตัวอย่าง PHP prepared statements

?php
        $mysqli = new mysqli("localhost", "username", "password", "database_name");
        $stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ? AND password = ?");

        $stmt->bind_param("ss", $username,$password); //ss บอกว่า parameter ตัวแรกและตัวที่สองคือ string ทั้งคู่

        $username = $_POST['user_username'];
        $password = $_POST['user_password'];

        $stmt->execute();

        if($stmt->fetch()){
                echo "Login Success";
        }else{
                echo "Login Fail";
        }
?>

จะเห็นได้ว่าการใช้ prepared statement เป็นการระบุให้กับเว็บแอปพลิเคชันรู้ก่อนว่า ข้อมูลที่ได้รับจากผู้ใช้งานนั้นเป็น string ทั้งหมดและไม่ให้นำข้อมูลที่เป็น string เหล่านี้ไปประมวลผลในรูปแบบของ SQL statement ดังนั้นโปรแกรมนี้จึงไม่มีช่องโหว่ประเภท SQL Injection

ไม่เพียงแต่ภาษา PHP เท่านั้นที่รองรับการทำ Prepared statements ภาษาอื่น ๆ ที่ใช้ในการเขียนเว็บเช่น .NET หรือ Java EE ก็มี prepared statement ให้เรียกใช้งาน

 2. Stored Procedure

Stored Procedure เป็นอีกหนึ่งวิธีการที่ใช้ในการป้องกัน SQL Injection โดย Stored Procedure จะเก็บ SQL query ไว้ที่ฐานข้อมูลและให้เว็บแอปพลิเคชันส่ง parameter มาให้ฐานข้อมูลเรียก SQL query ที่เก็บไว้มาทำงาน แทนที่เว็บแอปพลิเคชันจะเป็นผู้สร้าง SQL query แล้วส่งไปให้กับฐานข้อมูล

Stored Procedure เป็นวิธีการที่ไม่ค่อยได้รับความนิยมเท่ากับ Prepared Statement เนื่องจากต้องมีการสร้าง SQL query เก็บไว้ในฐานข้อมูลก่อนเรียกใช้ ทำให้การแก้ไข SQL query มีความยุ่งยากมากกว่า อย่างไรก็ตามฐานข้อมูลส่วนใหญ่ (MySQL, Oracle, DB2) ต่างก็รองรับการทำงานของ Stored Procedure

หากผู้อ่านสนใจเกี่ยวกับ Stored Procedure ของ MySQL และ PHP สามารถเข้าไปศึกษาต่อได้ที่ Link

3.Escaping User Input

Escaping User Input เป็นวิธีการที่ใช้ในการป้องกัน SQL Injection ด้วยการตรวจสอบข้อมูลที่ได้รับมาจากผู้ใช้งาน แก้ไข หรือ ลบ ข้อมูลที่อาจจะเป็นอันตรายออกก่อนที่จะนำไปสร้างเป็น SQL query หากเราลองสังเกตรูปแบบการโจมตีด้วย SQL Injection อักขระพิเศษ เช่น ‘ (single quote) หรือ ” (double quote) คือตัวการสำคัญในการพยายามดัดแปลง SQL query (นอกจากนี้ยังมี # — และ keyword อื่น ๆ เช่น AND OR) ดังนั้นหากเราสามารถที่จะกรองเครื่องหมายเหล่านี้ออกไปก่อนที่จะนำข้อมูลจากผู้ใช้งานไปสร้างเป็น SQL query ก็จะช่วยป้องกัน SQL Injection ได้มากขึ้น

อย่างไรก็ตาม Escaping User Input นั้นไม่มีประสิทธิภาพเมื่อเทียบกับสองวิธีแรกที่ได้อธิบายไป (Prepared Statements และ Stored Procedure) เนื่องจากข้อมูลที่ได้รับมาจากผู้ใช้งานนั้นมีรูปแบบที่หลากลายและมีการเปลี่ยนแปลงพัฒนาไปตามเวอร์ชันของฐานข้อมูล ทำให้การกรองข้อมูลผู้ใช้งานอาจจะไม่ครบถ้วนถูกต้องสมบูรณ์ ดังนั้น Escaping User Input ควรถูกเลือกเป็นตัวเลือกสุดท้ายในการป้องกัน SQL Injection และหากจำเป็นต้องใช้ Escaping User Input ก็ควรเลือกใช้ Library ที่น่าเชื่อถือ เช่น ESAPI จาก OWASP เป็นต้น

อ้างอิง

1. SQL Injection Prevention Cheat Sheet


Leave a Reply