ตาม document ของ PHP ถ้า magic_quotes_gpc ได้ถูกเปิดใช้งาน ตัวอักษร ' (single-quote), " (double-quote), \ (backslash) และ NULL ในข้อมูล GET, POST, COOKIE จะถูก escape ด้วย backslash อัตโนมัติ
กรณีที่ 1 SQL injection กับ MySQL
ผมขอเริ่มด้วยกรณีที่ magic_quotes_gpc ช่วยป้องกัน เรื่อง SQL injection ตัวอย่างนี้ PHP programmer ทุกๆ คนน่าจะเคยเห็นแล้ว
นั่นคือ code สำหรับการทำ authentication โดยข้อมูลอยู่ใน MySQL database (สมมติว่าเก็บ password เป็น plaintext)
// ... initialization and establishing database connection ... $result = mysql_query("SELECT * FROM account WHERE username='".$_GET['username']."' AND password='".$_GET['password']."'"); if (mysql_num_rows($result) > 0) { // authenticated } else { // login failed }ทดสอบด้วย classic SQL injection คือ username เป็น
adminและ password เป็น
' or 1=1#ถ้าปิด magic_quotes_gpc จะได้ SQL command เป็น
SELECT * FROM account WHERE username='admin' AND password='' or 1=1#'หลังเครื่องหมาย # ใน MySQL คือ comment จะไม่รวมใน SQL command และโดยทั่วไป (รวมถึง MySQL) operator precedence ของ AND จะสูงกว่า OR นั่นคือ AND จะถูกคิดก่อน OR ถ้าใส่วงเล็บให้ดูง่ายก็จะเป็น
SELECT * FROM account WHERE (username='admin' AND password='') or 1=1เนื่องจาก 1=1 เป็นจริงเสมอ ก็ทำให้ SQL command ของข้างบนเท่ากับ
SELECT * FROM accountซึ่งก็จะ login ผ่าน :)
ในทางกลับกัน ถ้าเปิด magic_quotes_gpc จะได้ SQL command เป็น
SELECT * FROM account WHERE username='admin' AND password='\' or 1=1'ก็จะ login ไม่ผ่าน :(
จะเห็นว่า ถ้าจะทำ SQL injection ในกรณีนี้ต้องมีการใช้ single-quote เข้าไปใน username หรือ password แต่ magic_quotes_gpc จะ escape single-quote ทำให้ไม่สามารถทำ SQL injection หรือพูดได้ว่า
magic_quotes_gpc ป้องกัน SQL injection ได้ ถ้า SQL injection ต้องใช้ตัวอักษร ' (single-quote), " (double-quote), \ (backslash) หรือ NULL
กรณีที่ 2 SQL injection กับ database อื่นๆ
ผมขอใช้ code เดิมจากกรณีที่ 1 แต่เปลี่ยน database เป็นตัวอื่นที่ escape single-quote ตาม SQL standard (เช่น Oracle, MSSQL) คือใช้ single-quote สองตัว เช่น 'O''hh' แต่ครั้งนี้ password ต้องเปลี่ยนเป็น
' or 1=1--(-- คือ comment ตาม SQL standard)
คราวนี้ขอแสดงเฉพาะกรณีเปิด magic_quotes_gpc ก็จะได้ SQL command เป็น
SELECT * FROM account WHERE username='admin' AND password='\' or 1=1--'สำหรับ database ที่ escape single-quote ตาม SQL standard จะมองว่า password คือ \ (backslash) ซึ่งก็จะ login ผ่านอยู่ดี :)
หลายคนอาจจะบอกว่า PHP กับ MSSQL ไม่น่าจะมีคนใช้ ส่วน Oracle ก็คงมีใช้น้อยมาก อันนี้ผมเห็นด้วย แล้ว PostgreSQL ละ
PostgreSQL ตอนแรกก็ใช้ backslash เพื่อที่จะ escape single-quote แต่ใน version 8 ก็จะมี option standard_conforming_strings ให้เลือกใช้แบบเดิม (สำหรับ backward compatibility) หรือแบบ SQL standard โดยที่ทาง PostgreSQL เองก็แนะนำให้ใช้ตาม standard
Note: PHP มี option magic_quotes_sybase เพื่อที่จะ escape single-quote สำหรับ database ที่ทำตาม standard
กรณีที่ 3 SQL injection กับข้อมูลที่เป็นตัวเลข
ตัวอย่างที่พบบ่อยๆ ของกรณีนี้ คือการแสดงข้อมูลตาม id ที่อยู่ใน database โดยที่ PHP code ที่ทำ SQL query เป็นดังนี้
mysql_query("SELECT col1, col2, col3 FROM data WHERE id=".$_GET['id']);ทดสอบด้วยการใส่ค่า id เป็น
0 UNION SELECT username,password,1 FROM accountจะได้ SQL command เป็น
SELECT col1, col2, col3 FROM data WHERE id=0 UNION SELECT username,password,1 FROM accountสมมติว่าใน database ไม่มี id ที่เป็น 0 SQL command ก็จะเป็น
SELECT username,password,1 FROM accountทำให้แทนที่จะดึงข้อมูลจาก data table ก็กลายเป็นดึงข้อมูลมาจาก account table มาแสดงผล
จะเห็นว่า id เป็นตัวเลข และโดยส่วนมาก programmer ไม่ได้ใส่ single-quote สำหรับตัวเลข ดังนั้น SQL injection ไม่ต้องมี single-quote ก่อนที่จะเพิ่ม SQL command และ magic_quotes_gpc ก็ไม่สามารถช่วยป้องกันในกรณีได้ เพราะไม่มีตัวอักษรที่ต้อง escape
ตัวอย่างอื่นๆ ของ SQL injection กับข้อมูลที่เป็นตัวเลข คือเวลาแสดงข้อมูลเป็นหลายๆ หน้า ตัวเว็บจะมีการรับหน้า และจำนวนข้อมูลต่อหน้า
กรณีที่ 4 SQL injection กับ SQL operator
กรณีนี้ส่วนมากจะพบในหน้า Advanced Search ของเว็บที่ให้ผู้ใช้สามารถใส่หลายๆ เงื่อนไขในการค้นหา และสามารถเลือกได้ว่าจะนำมา AND หรือ OR โดยที่ทางเว็บส่ง AND หรือ OR ตรงๆ เช่น
HTML code snippet: col1: <input name="col1" type="text" /><br/> <input checked="checked" name="oper" type="radio" value="AND" /> และ <input name="oper" type="radio" value="OR" /> หรือ<br/> col2: <input name="col2" type="text" />
PHP code snippet: $result = mysql_query("SELECT col1, col2, col3 FROM data WHERE col1='%".$_POST['col1']."%' ".$_POST['oper']." col2='%".$_POST['col2']."%'");จากตัวอย่างผู้ใช้สามารถเงื่อนไขของ col1 กับ col2 และมี radio box เพื่อเลือก AND หรือ OR โดยตัวอย่าง SQL injection ก็คือแก้ไขค่า oper เป็น
UNION SELECT username,password,1 FROM account#ทำให้ SQL command เป็น
SELECT col1, col2, col3 FROM data WHERE col1='%cond1%' UNION SELECT username,password,1 FROM account# col2='%cond2%'ซึ่งก็คือค้นหาข้อมูลใน data table ตาม cond1 และข้อมูลใน account table ทั้งหมด
Note: ถ้า SQL command ใน PHP code ซับซ้อนกว่านี้ การทำ SQL injection ก็ยังเป็นไปได้ แค่อาจต้องเพิ่มบางส่วน เช่น วงเล็บ เพื่อให้ SQL syntax พร้อมกับทำ injection
จะเห็นว่ากรณีนี้ ก็เป็นอีกกรณีหนึ่งที่ magic_quotes_gpc ไม่สามารถป้องกัน SQL injection ได้
จากตัวอย่างทั้งหมดที่กล่าวมา คงทำให้เห็นกันแล้วว่า magic_quotes_gpc ช่วยและไม่ช่วยป้องกัน SQL injection ยังไง (จริงๆ คือนึกไม่ออกแล้ว)
ถ้ามีการเปิด magic_quotes_gpc ก็ยังสามารถทำ SQL injection ถ้าไม่จำเป็นต้องใช้ตัวอักษรที่ถูก escape
และก็จะจบก็คงต้องเขียนวิธีป้องกัน ที่มีอยู่หลักเดียวง่ายๆ คือตรวจสอบ หรือ filter input ที่มาจากผู้ใช้ทั้งหมด ก่อนนำมาประมวลผล
วิธีการป้องกันตามตัวอย่างที่ได้ยกมา (สมมติว่าไม่มีการใช้ magic_quotes_gpc)
1. สำหรับข้อมูลที่เป็นตัวอักษร ใช้
mysql_real_escape_string()ก่อนที่ใช้นำไปใส่ใน SQL command
2. สำหรับข้อมูลตัวเลข ให้ทำการ cast เป็นตัวเลขก่อนด้วยการใช้
(int)หรือ
(integer)หรือใช้
intval()function
3. สำหรับข้อมูลที่เป็นส่วนหนึ่งของ SQL syntax ก็ให้ตรวจสอบว่าเป็นที่เราอนุญาตหรือไม่ เช่นตัวอย่างในกรณีที่ 4 ก็ตรวจสอบว่าค่า oper เป็น AND หรือ OR เท่านั้น
สุดท้ายการที่ทาง PHP จะเอา magic_quotes_* ออกนั้น น่าจะเป็นเพราะว่า (อันนี้ความคิดผม) มันทำให้ programmer เข้าใจผิด และอาจทำให้สับสน รวมทั้งข้อมูลที่รับมาอาจจะไม่ได้เอามาใช้กับ database เช่น save ลงไฟล์ ทำให้ programmer ต้องมาแก้ไขข้อมูลให้ถูกต้องอีกด้วย
stripslashes()
เนื้อหาดีมากครับ
ReplyDeleteเนื้อหาดีครับ
ReplyDeleteIt’s hard to come by experienced people about this subject, but you seem like you know what you’re talking about! Thanks.
ReplyDeleteJava Training in Bangalore