ล่าสุดการพัฒนาเว็บบทเรียน
 

SQLการฉีด


การฉีด SQL สามารถทำลายฐานข้อมูลของคุณ


SQL ในหน้าเว็บ

ในบทที่ก่อนหน้านี้คุณได้เรียนรู้ที่จะดึง (และแก้ไข) ข้อมูลในฐานข้อมูลโดยใช้ SQL

เมื่อ SQL จะใช้ในการแสดงข้อมูลบนหน้าเว็บมันเป็นเรื่องธรรมดาที่จะให้ผู้ใช้งานป้อนค่าเว็บค้นหาของพวกเขาเอง

เนื่องจากคำสั่ง SQL มีข้อความเท่านั้นมันเป็นเรื่องง่ายที่มีชิ้นเล็ก ๆ ของรหัสคอมพิวเตอร์แบบไดนามิกเปลี่ยนคำสั่ง SQL เพื่อให้ผู้ใช้ที่มีข้อมูลที่เลือก:

เซิร์ฟเวอร์รหัส

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

ตัวอย่างข้างต้นสร้างคำสั่งเลือกโดยการเพิ่มตัวแปร (txtUserId) เป็นสตริงที่เลือก ตัวแปรคือความจริงจากผู้ใช้ป้อน (Request) ไปยังหน้า

ส่วนที่เหลือของบทนี้อธิบายถึงอันตรายที่อาจเกิดจากการใช้การป้อนข้อมูลของผู้ใช้ในคำสั่ง SQL


SQL Injection

ฉีด SQL เป็นเทคนิคที่ผู้ใช้ที่เป็นอันตรายสามารถฉีดเข้าไปในคำสั่ง SQL คำสั่ง SQL ที่ผ่านการป้อนข้อมูลของหน้าเว็บ

คำสั่ง SQL ฉีดสามารถปรับเปลี่ยนคำสั่ง SQL และยอมความปลอดภัยของแอพลิเคชันเว็บ


ฉีด SQL ขึ้นอยู่กับ 1 = 1 เป็นจริงเสมอ

ดูตัวอย่างข้างต้นอีกครั้งหนึ่ง

สมมติว่าวัตถุประสงค์ดั้งเดิมของรหัสคือการสร้างคำสั่ง SQL เพื่อเลือกผู้ใช้ที่มีรหัสผู้ใช้ที่กำหนด

ถ้ามีอะไรที่จะป้องกันไม่ให้ผู้ใช้จากการป้อน "wrong" การป้อนข้อมูลผู้ใช้สามารถป้อน "smart" ป้อนข้อมูลเช่นนี้

หมายเลขผู้ใช้:

ผลเซิร์ฟเวอร์

SELECT * FROM Users WHERE UserId = 105 or 1=1

ของ SQL ข้างต้นเป็นที่ถูกต้อง มันจะกลับมาแถวทั้งหมดจากผู้ใช้ตารางตั้งแต่ WHERE 1 = 1 เป็นความจริงเสมอ

ไม่ตัวอย่างข้างต้นดูเหมือนอันตรายหรือไม่? เกิดอะไรขึ้นถ้าตารางมีชื่อผู้ใช้และรหัสผ่าน?

คำสั่ง SQL ข้างต้นเป็นมากเช่นเดียวกับนี้:

SELECT UserId, Name, Password FROM Users WHERE UserId = 105 or 1=1

แฮ็กเกอร์มาร์ทอาจได้รับการเข้าถึงทุกชื่อผู้ใช้และรหัสผ่านในฐานข้อมูลโดยการใส่ 105 หรือ 1 = 1 ลงในช่องป้อนข้อมูล


ฉีด SQL ขึ้นอยู่กับ ""="" เป็นจริงเสมอ

นี่คือการก่อสร้างทั่วไปที่ใช้ในการตรวจสอบการเข้าสู่ระบบของผู้ใช้ไปยังเว็บไซต์:

ชื่อผู้ใช้:

รหัสผ่าน:

เซิร์ฟเวอร์รหัส

uName = getRequestString("UserName");
uPass = getRequestString("UserPass");

sql = "SELECT * FROM Users WHERE Name ='" + uName + "' AND Pass ='" + uPass + "'"

แฮ็กเกอร์มาร์ทอาจจะได้รับการเข้าถึงชื่อผู้ใช้และรหัสผ่านในฐานข้อมูลโดยการใส่ "หรือ ""=" เข้าไปในชื่อผู้ใช้หรือรหัสผ่านกล่องข้อความ

รหัสที่เซิร์ฟเวอร์จะสร้างคำสั่ง SQL ที่ถูกต้องเช่นนี้

ผล

SELECT * FROM Users WHERE Name ="" or ""="" AND Pass ="" or ""=""

ของ SQL ผลที่ถูกต้อง มันจะกลับมาแถวทั้งหมดจากผู้ใช้ตารางตั้งแต่ที่ไหน "" = "" เป็นจริงเสมอ


ฉีด SQL จากงบ SQL เป็นแบทช์

ฐานข้อมูลส่วนใหญ่สนับสนุนคำสั่ง SQL เป็นแบทช์, คั่น

ตัวอย่าง

SELECT * FROM Users; DROP TABLE Suppliers

ของ SQL ดังกล่าวข้างต้นจะกลับแถวทั้งหมดในตารางผู้ใช้แล้วลบตารางเรียกว่าซัพพลายเออร์

ถ้าเรามีรหัสเซิร์ฟเวอร์ต่อไปนี้:

เซิร์ฟเวอร์รหัส

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;

และป้อนข้อมูลต่อไปนี้:

รหัสผู้ใช้:

รหัสที่เซิร์ฟเวอร์จะสร้างคำสั่ง SQL ที่ถูกต้องเช่นนี้

ผล

SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers

พารามิเตอร์สำหรับการป้องกัน

นักพัฒนาเว็บบางคนใช้ "blacklist" ของคำหรือตัวอักษรเพื่อค้นหาในการป้อนข้อมูล SQL เพื่อป้องกันการโจมตีฉีด SQL

นี้ไม่ได้เป็นความคิดที่ดีมาก หลายของคำเหล่านี้ (เช่นลบหรือลดลง) และตัวอักษร (เช่นอัฒภาคและเครื่องหมายอัญประกาศ) ถูกนำมาใช้ในภาษาทั่วไปและควรได้รับอนุญาตในหลายประเภทของการป้อนข้อมูล

(ในความเป็นจริงมันควรจะเป็นอย่างสมบูรณ์ตามกฎหมายในการป้อนคำสั่ง SQL ในด้านฐานข้อมูล.)

วิธีการพิสูจน์เดียวที่จะปกป้องเว็บไซต์จากการโจมตีฉีด SQL คือการใช้พารามิเตอร์ SQL

พารามิเตอร์ SQL มีค่าที่จะมีการเพิ่มแบบสอบถาม SQL ในเวลาการดำเนินการในลักษณะที่ควบคุม

ASP.NET ตัวอย่างมีดโกน

txtUserId = getRequestString("UserId");
txtSQL = "SELECT * FROM Users WHERE UserId = @0";
db.Execute(txtSQL,txtUserId);

โปรดทราบว่าพารามิเตอร์จะแสดงในคำสั่ง SQL โดยเครื่องหมาย @

โปรแกรม SQL ตรวจสอบแต่ละพารามิเตอร์เพื่อให้มั่นใจว่ามันเป็นสิ่งที่ถูกต้องสำหรับคอลัมน์และได้รับการปฏิบัติอย่างแท้จริงและไม่เป็นส่วนหนึ่งของ SQL ที่จะดำเนินการ

ตัวอย่างอื่น

txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
db.Execute(txtSQL,txtNam,txtAdd,txtCit);

คุณได้เรียนรู้เพียงเพื่อหลีกเลี่ยงการฉีด SQL หนึ่งในช่องโหว่บนเว็บไซต์


ตัวอย่าง

ตัวอย่างต่อไปนี้แสดงให้เห็นถึงวิธีการสร้างแบบสอบถามในภาษาบางเว็บทั่วไป

คำสั่ง SELECT ใน ASP.NET:

txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserID);
command.ExecuteReader();

แทรกลงในคำสั่งใน ASP.NET:

txtNam = getRequestString("CustomerName");
txtAdd = getRequestString("Address");
txtCit = getRequestString("City");
txtSQL = "INSERT INTO Customers (CustomerName,Address,City) Values(@0,@1,@2)";
command = new SqlCommand(txtSQL);
command.Parameters.AddWithValue("@0",txtNam);
command.Parameters.AddWithValue("@1",txtAdd);
command.Parameters.AddWithValue("@2",txtCit);
command.ExecuteNonQuery();

แทรกลงในคำสั่งใน PHP:

$stmt = $dbh->prepare("INSERT INTO Customers (CustomerName,Address,City)
VALUES (:nam, :add, :cit)");
$stmt->bindParam(':nam', $txtNam);
$stmt->bindParam(':add', $txtAdd);
$stmt->bindParam(':cit', $txtCit);
$stmt->execute();