ในปัจจุบันที่ระบบฐานข้อมูลเป็นหัวใจสำคัญในการเก็บข้อมูลต่าง ๆ ของเว็บไซต์ ช่องโหว่หนึ่งที่แฮกเกอร์มักใช้ในการโจมตีเว็บไซต์เหล่านี้ก็คือการทำ SQL Injection การโจมตีด้วยวิธีดังกล่าวแฮกเกอร์สามารถตรวจสอบว่าเว็บใด ๆ มีช่องโหว่ที่สามารถทำ SQL Injection ได้หรือไม่ได้อย่างง่ายดายและการโจมตีด้วย SQL Injection ก็ไม่ใช่เป็นเรื่องที่ยากเย็นอะไร แต่ผลลัพท์ที่ได้นั่นรุนแรงทีดียว ปัญหาก็คือโปรแกรมเมอร์มือใหม่ส่วนใหญ่ไม่รู้ด้วยซ้ำว่า SQL Injection คืออะไร? การโจมตีแบบ SQL Injection คือการที่ hacker ใช้ช่องโหว่ของโปรแกรมทำให้สามารถเติมคำสั่งภาษา SQL เข้าไปทางส่วนรับข้อมูลขาเข้า(input)ของโปรแกรมได้. หากเว็บแอพพลิเคชั่นที่เปิดช่องให้แฮกเกอร์ทำการโจมตีแบบนี้ได้ ก็จะทำให้แฮกเกอร์สามารถอ่านข้อมูลสำคัญต่าง ๆ ในระบบฐานข้อมูล (SELECT), แก้ไบข้อมูลต่าง ๆ ในระบบฐานข้อมูล( INSERT/UPDATE/DELETE), เรียกคำสั่งที่ใช้ในการจัดการระบบฐานข้อมูลเช่นคำสั่งสำรองข้อมูล (backup) หรือแม้กระทั่งเรียกคำสั่งของระบบปฎิบัติการได้ในบางกรณื. SQL Injection จะเกิดขึ้นได้ต้องมีปัจจัยสองประการ
แฮกเกอร์จึงสามารถใช้ข้อบกพร่องข้างต้นสร้างข้อมูลที่จะป้อนให้กับโปรแกรมแบบพิเศษเพื่อทำให้เรียกใช้คำสั่ง SQL ต่างๆ เพิ่มเติมจากที่โปรแกรมปกติเรียกใช้ได้ ตัวอย่างด้านล่างคือ ส่วนของโปรแกรมภาษาจาวาที่้ใช้ในการตรวจสอบผู้ใช้ (Authenticate) ทั่วๆไป แต่โปรแกรมดังกล่าวมีข้อบกพร่องที่แฮกเกอร์สามารถใช้เป็นช่องทางในการโจมตีแบบ SQL Injection ได้
String DRIVER = "com.ora.jdbc.Driver";
String DataURL = "jdbc:db://localhost:5112/users";
String LOGIN = "admin";
String PASSWORD = "admin123";
Class.forName(DRIVER);
//Make connection to DB
Connection connection = DriverManager.getConnection(DataURL, LOGIN, PASSWORD);
String Username = request.getParameter("USER"); // From HTTP request
String Password = request.getParameter("PASSWORD"); // From HTTP request
int iUserID = -1;
String sLoggedUser = "";
String queryString = "SELECT User_id, Username FROM USERS "
+ " WHERE Username = '" +Username
+ "' AND Password = '" + Password + "'";
Statement selectStatement = connection.createStatement ();
ResultSet resultSet = selectStatement.executeQuery(queryString);
if (resultSet.next()) {
iUserID = resultSet.getInt(1);
sLoggedUser = resultSet.getString(2);
}
PrintWriter writer = response.getWriter ();
if (iUserID >= 0) {
writer.println ("User logged in: " + sLoggedUser);
} else {
writer.println ("Access Denied!")
}
เมื่อโปรแกรมดังกล่าวถูกเรียกใช้ จะเห็นว่ามีการรับข้อมูลมาจาก HTTP Request มาสองอันคือ Username กับ Password หลังจากนั้นข้อมูลทั้งสองถูกนำไปใช้ในการสร้างคำสั่งภาษา SQL โดยตรงโดยไม่ได้มีการตรวจสอบก่อนว่าข้อมูลที่รับเข้ามาทาง HTTP Request ทั้งสองนั้นปลอดภัยหรือไม่ (ไม่ได้ตรวจสอบว่ามีตัวอักษรที่เป็นอันตรายในการสร้างคำสั่ง SQL หรือไม่ นอกจากนี้ยังไม่ได้ตรวจสอบความยาวของข้อมูลด้วยว่า ความยาวของข้อมูลที่รับมานั้นสั้นหรือยาวเกินไปหรือไม่ ข้อมูลที่ยาวเกินไปอาจจะทำให้เกิดปัญหาอื่น ๆ เช่น Buffer Overflow เป็นต้น)
SELECT User_id, Username FROM USERS WHERE Username = 'John' AND Password = 'Smith123'
ซึ่งคำสั่งดังกล่าวจะไปดึงข้อมูลมาจากตารางที่ชื่อว่า USERS ที่มีค่าของฟิลด์ที่ชื่อว่า Username เท่ากับ 'John' และค่าของฟิลด์ที่ชื่อว่า Password = 'Smith123' ซึ่งถ้าในฐานข้อมูลมีข้อมูลดังกล่าวอย่างน้อย 1 เรคคอร์ด ผู้ใช้ก็จะสามารถเข้าสู่ระบบได้
SELECT User_id, Username FROM USERS WHERE Username = 'nobody' AND Password = 'nopassword' OR 'a' = 'a'
ผลลัพธ์ที่คืนมากจากคำสั่ง SQL ด้านบนนั้นคือข้อมูลทุกเรคคอร์ดในตาราง USERS เนื่องจากในภาษา SQL นั้น OR operation มี precedence ต่ำกว่า AND operation และ 'a'='a' เป็นนิพจน์ที่เป็นจริงเสมอ ดังนั้นการ OR ด้วยนิพจน์ที่เป็นจริงเสมอจึงทำให้ระบบฐานข้อมูลคือข้อมูลทุกเรคคอร์ดในตาราง USERS และทำให้ผู้ใช้เ้ข้าสู่ระบบได้เหมือนผู้ใช้ทั่วไปโดยที่ไม่ต้องใส่ Username กับ Password ให้มีอยู่ในระบบฐานข้อมูลเลย แต่ก็มีคำถามที่เกิดขึ้นก็คือ ในกรณีนี้แฮกเกอร์เข้าไปในระบบโดยได้สิทธิของผู้ใช้คนไหน? คำตอบก็คือ เขาได้สิทธิเป็นผู้ใช้ที่มี Username ตรงกับข้อมูลเรคคอร์ดแรกที่ระบบฐานข้อมูลคืนมาให้ด้วยคำสั่ง SQL ดังกล่าว การป้องกัน SQL Injection ที่ถูกวิธี1. ใช้ Parameterized Queries แทนระบบฐานข้อมูลและ ภาษาคอมพิวเตอร์ส่วนใหญ่มักจัดเตรียม API ที่ในการติดต่อระบบฐานข้อมูลอย่างถูกวิธีเพื่อป้องกันการโจมตีด้วย SQL Injection ไว้ให้แล้ว ที่เรียกว่า Parameterized Queries หรือ Prepared Statements ซึ่งวิธีดังกล่าวจะมีขั้นตอนในการสร้างคำสั่งภาษา SQL ดังนี้
ต่อไปนี้จะเป็นตัวอย่างการแก้ไขข้อบกพร่องของโปรแกรมด้านบนโดยเปลี่ยนมาใช้ Parameterized Queries แทน
/*กำหนดโครงสร้างของคำสั่ง SQL โดยเครื่องหมายคำถาม (?) จะแทนตำแหน่งที่จะถูกแทนที่ด้วยข้อมูลที่รับเข้ามา*/
String queryString = "SELECT User_id, Username FROM USERS "
+ " WHERE Username = ?"
+ " AND Password = ?";
/*สร้าง Parameterized Query*/
PreparedStatement pstmt = connection.prepareStatement(queryString );
/* แทนที่ค่าต่าง ๆ ลงในตำแหน่งที่เตรียมไว้*/
pstmt.setString(1, Username);
pstmt.setString(2, Password);
ResultSet resultSet = pstmt.executeQuery();
2. กำหนดสิทธิของโปรแกรมในการติดต่อกับระบบฐานข้อมูลให้มีสิทธิน้อยที่สุดเท่าที่จะเป็นไปได้โดยปกติแล้วโปรแกรมต่าง ๆ ไม่จำเป็นที่จะต้อมีสิทธิในการเรียกใช้คำสั่ง SQL เท่ากับผู้ดูแลระบบฐานข้อมูล (DBA) ยกตัวอย่างเช่นหากเว็บไซต์ของคุณเป็นเพียงแค่เว็บไซต์ที่ใช้แสดงข้อมูลสินค้า และสั่งซื้อผ่านอินเตอร์เน็ต และจำเป็นต้องลงทะเบียนผู้ใช้ก่อนซื้อ ในการกำหนดสิทธืของเว็บไซต์นี้ ก็ควรกำหนดให้มีสิทธิอ่านอย่างเดียวสำหรับตารางข้อมูลสินค้า สิทธิอ่าน/เขียนสำหรับตารางข้อมูลการสั่งซื้อและตางรางข้อมูลลูกค้า และไม่มีสิทธิใด ๆ เลยใน table อื่น ๆ ที่ไม่เกี่ยวข้องเป็นต้น 3. ทำการ Hardening Databaseระบบฐานข้อมูลบางอันอาจจะมีความสามารถพิเศษต่าง ๆ เช่นสามารถเรียกใช้คำสั่งของระบบปฎิบัติการเป็นต้น ถ้าความสามารถพิเศษเหล่านี้ไม่จำเป็นต้องใช้ก็ต้องปิดมัน และหมั่นทำการ patch ระบบฐานข้อมูลเป็นประจำเพื่อป้องกันการโจมตีด้วย Known-exploits |
|||
Related Links |
||
|
|
ขอบคุณค่ะ
ได้ความรู้ขึ้นเยอะเลยคุ่ะ
:)
Post new comment