SQL Injection (2)
บทความนี้อาจเป็นอันตรายต่อเครื่องคอมพิวตอร์ของคุณ โปรดใช้พิจารณญาณในการอ่านบทความนี้
บทความนี้ไม่ได้มุ่งหวังเพื่อให้เกิดผลเสียแก่ใครหรือกระทั่งเว็บตัวอย่าง ผมไม่ได้กระทำการทดสอบกับเว็บตัวอย่างจริงๆ เพียงแต่บอกเล่าตามที่มีคนบอกมาอีกที
จุดประสงค์ของบทความนี้เพื่อเป็นตัวอย่าง และใช้ความระมัดระวังกับเว็บไซต์ของตัวเองเท่านั้น
พอดีวันนี้มีรุ่นน้องคนนึง มาถามผมว่ารู้จัก เจ้าของเว็บ เว็บนึงมั้ย เขาบอกว่าเขาสามารถ hack เว็บนึงได้ เขาแจ้งไปแล้วแต่ทางเว็บเจ้าของเพิกเฉย เขาก็เลยเอามาเล่าให้ผมฟัง
เขาบอกผมว่าที่เขาพบ มันเป็น SQL Injection ซึ่งก็หมายถึงการ Hack เว็บผ่าน MySQL และก็ค่อนข้างอันตรายด้วย เพราะสิ่งที่ได้มาเป็นชื่อ หรือ รหัสผ่านของแอดมิน ถ้าเป็นเว็บที่สำคัญก็ค่อนข้างอันตรายมั้ยครับ
มาดูโค้ดกันก่อนเลย
เป็นการ hack โดยผ่าน query ธรรมดาครับ ปัญหาของกรณีนี้เกิดจากการไม่ได้ตรวจสอบ query ที่ส่งเข้ามาก่อน ในที่นี้คือส่งผ่านตัวแปร category เมือรับเอาไปแล้วก็ไปประมวลผล SQL เลย ทำให้ได้ผลลัพท์ที่ไม่พึงประสงค์ออกมา
โค้ดในส่วนที่รับค่ามาประมวลผลมี ดังนี้
จะเห็นได้ว่าเมื่อรับ query เข้ามาแล้วไม่ได้มีการตรวจสอบใดๆ แล้วยังเอามาใส่ลงใน query เลย ผลลัพท์เมื่อเอาใส่ลง query แล้วเป็นดังนี้
นอกจากนี้ ในตอนแสดงผลยังเอาค่าที่ query ได้ออกมาแสดงตรงๆ อีก
ซึ่งทั้ง 2 วิธีเป็นการแสดงผลลัพท์โดยไม่ได้ระบุชื่อฟิลด์ที่ต้องการ ซึ่งหากมีผลลัพท์ออกมา มันก็สามารถแสดงผลได้ทันที ซึ่งอาจไม่ใช่ผลลัพท์ที่ต้องการก็ได้
ปัญหาที่เกิดผมเข้าใจว่าผู้ออกแบบคงคาดว่าค่าตัวแปร category จะเป้นตัวเลขเพียงอย่างเดียว ก็เลยไม่ได้ทดสอบอะไร แต่ในความเป็นจริงค่อนข้างอันตราย เพราะเป็นการเปิดช่องให้ผู้ไม่หวังดีใช้ช่องทางนี้ได้
สำหรับการป้องกัน ก็ไม่มีอะไรมาก
1. ทำการทดสอบตัวแปรด้วย (int)
เพื่อรับค่าที่เป็นตัวเลขเท่านั้น
2.ใส่ ' (quote) ครอบตัวแปร เพื่อกำหนดขอบเขตของตัวแปร หากเป็นสตริงค์ หรือหากเป็นตัวเลขก็ได้
ส่วนในการแสดงผล ควรระบุชื่อฟิลด์เพื่อรับค่า
ขอให้โชคดีมีชัยนะครับ
บทความนี้ไม่ได้มุ่งหวังเพื่อให้เกิดผลเสียแก่ใครหรือกระทั่งเว็บตัวอย่าง ผมไม่ได้กระทำการทดสอบกับเว็บตัวอย่างจริงๆ เพียงแต่บอกเล่าตามที่มีคนบอกมาอีกที
จุดประสงค์ของบทความนี้เพื่อเป็นตัวอย่าง และใช้ความระมัดระวังกับเว็บไซต์ของตัวเองเท่านั้น
พอดีวันนี้มีรุ่นน้องคนนึง มาถามผมว่ารู้จัก เจ้าของเว็บ เว็บนึงมั้ย เขาบอกว่าเขาสามารถ 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;
ขอให้โชคดีมีชัยนะครับ