SQL Injection (2)

บทความนี้อาจเป็นอันตรายต่อเครื่องคอมพิวตอร์ของคุณ โปรดใช้พิจารณญาณในการอ่านบทความนี้

บทความนี้ไม่ได้มุ่งหวังเพื่อให้เกิดผลเสียแก่ใครหรือกระทั่งเว็บตัวอย่าง ผมไม่ได้กระทำการทดสอบกับเว็บตัวอย่างจริงๆ เพียงแต่บอกเล่าตามที่มีคนบอกมาอีกที

จุดประสงค์ของบทความนี้เพื่อเป็นตัวอย่าง และใช้ความระมัดระวังกับเว็บไซต์ของตัวเองเท่านั้น




อดีวันนี้มีรุ่นน้องคนนึง มาถามผมว่ารู้จัก เจ้าของเว็บ เว็บนึงมั้ย เขาบอกว่าเขาสามารถ hack เว็บนึงได้ เขาแจ้งไปแล้วแต่ทางเว็บเจ้าของเพิกเฉย เขาก็เลยเอามาเล่าให้ผมฟัง

เขาบอกผมว่าที่เขาพบ มันเป็น SQL Injection ซึ่งก็หมายถึงการ Hack เว็บผ่าน MySQL และก็ค่อนข้างอันตรายด้วย เพราะสิ่งที่ได้มาเป็นชื่อ หรือ รหัสผ่านของแอดมิน ถ้าเป็นเว็บที่สำคัญก็ค่อนข้างอันตรายมั้ยครับ

มาดูโค้ดกันก่อนเลย

index.php?name=xxx&category=1+and+1=2+union+select+concat(username,0x3A,password)+from+tablename/*

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

โค้ดในส่วนที่รับค่ามาประมวลผลมี ดังนี้

"SELECT xxx FROM ".xxx." WHERE id=".$_GET[category]." ";

จะเห็นได้ว่าเมื่อรับ query เข้ามาแล้วไม่ได้มีการตรวจสอบใดๆ แล้วยังเอามาใส่ลงใน query เลย ผลลัพท์เมื่อเอาใส่ลง query แล้วเป็นดังนี้

SELECT xxx FROM xxx WHERE id=1 and 1=2 union select concat(username,0x3A,password) from web_admin/*


นอกจากนี้ ในตอนแสดงผลยังเอาค่าที่ query ได้ออกมาแสดงตรงๆ อีก

$array = mysql_fetch_array( $query );
echo $array[0];

// หรือการใช้

$result = mysql_result( $query , 0 , 0 );
echo $result;

ซึ่งทั้ง 2 วิธีเป็นการแสดงผลลัพท์โดยไม่ได้ระบุชื่อฟิลด์ที่ต้องการ ซึ่งหากมีผลลัพท์ออกมา มันก็สามารถแสดงผลได้ทันที ซึ่งอาจไม่ใช่ผลลัพท์ที่ต้องการก็ได้

ปัญหาที่เกิดผมเข้าใจว่าผู้ออกแบบคงคาดว่าค่าตัวแปร category จะเป้นตัวเลขเพียงอย่างเดียว ก็เลยไม่ได้ทดสอบอะไร แต่ในความเป็นจริงค่อนข้างอันตราย เพราะเป็นการเปิดช่องให้ผู้ไม่หวังดีใช้ช่องทางนี้ได้

สำหรับการป้องกัน ก็ไม่มีอะไรมาก
1. ทำการทดสอบตัวแปรด้วย (int)

$category = (int)$_GET[category];

เพื่อรับค่าที่เป็นตัวเลขเท่านั้น
2.ใส่ ' (quote) ครอบตัวแปร เพื่อกำหนดขอบเขตของตัวแปร หากเป็นสตริงค์ หรือหากเป็นตัวเลขก็ได้

"SELECT xxx FROM ".xxx." WHERE id='".$_GET[category]."' ";

ส่วนในการแสดงผล ควรระบุชื่อฟิลด์เพื่อรับค่า

$array = mysql_fetch_array( $query );
echo $array[category];

// หรือการใช้

$result = mysql_result( $query , 0 , 'category' );
echo $result;


ขอให้โชคดีมีชัยนะครับ
ผู้เขียน goragod โพสต์เมื่อ 28 พ.ค. 2551 เปิดดู 16,346 ป้ายกำกับ SQLHACK
^