MySQL - และ SQL Injection
หากคุณรับข้อมูลผู้ใช้ผ่านหน้าเว็บและแทรกลงในฐานข้อมูล MySQL มีโอกาสที่คุณจะเปิดกว้างสำหรับปัญหาด้านความปลอดภัยที่เรียกว่า SQL Injection. บทนี้จะสอนวิธีช่วยป้องกันไม่ให้สิ่งนี้เกิดขึ้นและช่วยให้สคริปต์และคำสั่ง MySQL ของคุณปลอดภัย
SQL Injection มักเกิดขึ้นเมื่อคุณขอให้ผู้ใช้ป้อนข้อมูลเช่นชื่อของพวกเขาและแทนที่จะเป็นชื่อพวกเขาให้คำสั่ง MySQL แก่คุณซึ่งคุณจะเรียกใช้ฐานข้อมูลของคุณโดยไม่รู้ตัว
อย่าเชื่อถือข้อมูลที่ผู้ใช้ให้มาประมวลผลข้อมูลนี้หลังจากการตรวจสอบความถูกต้องเท่านั้น ตามกฎแล้วสิ่งนี้ทำได้โดยการจับคู่รูปแบบ ในตัวอย่างต่อไปนี้ชื่อผู้ใช้ถูก จำกัด ไว้ที่อักขระที่เป็นตัวอักษรและตัวเลขคละกันบวกขีดล่างและมีความยาวระหว่าง 8 ถึง 20 อักขระ - แก้ไขกฎเหล่านี้ได้ตามต้องการ
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
$result = mysql_query("SELECT * FROM users WHERE username = $matches[0]");
} else {
echo "username not accepted";
}
เพื่อแสดงให้เห็นปัญหานี้ให้พิจารณาข้อความที่ตัดตอนมาต่อไปนี้
// supposed input
$name = "Qadir'; DELETE FROM users;";
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
การเรียกใช้ฟังก์ชันควรจะดึงข้อมูลจากตารางผู้ใช้โดยที่คอลัมน์ชื่อตรงกับชื่อที่ผู้ใช้ระบุ ภายใต้สถานการณ์ปกติ $ name จะมีเฉพาะอักขระที่เป็นตัวเลขและตัวอักษรและอาจเว้นวรรค แต่ที่นี่ด้วยการต่อท้ายข้อความค้นหาใหม่ทั้งหมด$nameการโทรไปยังฐานข้อมูลกลายเป็นหายนะ การสอบถาม DELETE ที่แทรกจะลบระเบียนทั้งหมดจากผู้ใช้
โชคดีถ้าคุณใช้ MySQL ไฟล์ mysql_query()ฟังก์ชันไม่อนุญาตให้มีการซ้อนคิวรีหรือเรียกใช้การสืบค้นหลายรายการในการเรียกฟังก์ชันเดียว หากคุณพยายามซ้อนคิวรีการโทรล้มเหลว
อย่างไรก็ตามส่วนขยายฐานข้อมูล PHP อื่น ๆ เช่น SQLite และ PostgreSQLดำเนินการค้นหาแบบเรียงซ้อนอย่างมีความสุขดำเนินการค้นหาทั้งหมดที่มีให้ในสตริงเดียวและสร้างปัญหาด้านความปลอดภัยที่ร้ายแรง
การป้องกัน SQL Injection
คุณสามารถจัดการอักขระ Escape ทั้งหมดได้อย่างชาญฉลาดในภาษาสคริปต์เช่น PERL และ PHP ส่วนขยาย MySQL สำหรับ PHP มีฟังก์ชันmysql_real_escape_string() เพื่อหลีกเลี่ยงอักขระอินพุตที่พิเศษสำหรับ MySQL
if (get_magic_quotes_gpc()) {
$name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM users WHERE name = '{$name}'");
ชอบความไม่แน่ใจ
ในการจัดการกับปัญหา LIKE กลไกการหลีกเลี่ยงที่กำหนดเองต้องแปลงอักขระ% และ _ ที่ผู้ใช้จัดหาให้เป็นตัวอักษร ใช้addcslashes()ซึ่งเป็นฟังก์ชันที่ให้คุณระบุช่วงอักขระที่จะหลบหนี
$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");