Categories SQL

SQL Injection là gì?

SQL Injection có thể phá huỷ cơ sở dữ liệu của bạn. 


SQL trong các trang web

Trong các bài trước, bạn đã học cách lấy (và cập nhật) cơ sở dữ liệu, sử dụng SQL.

Khi SQL được sử dụng để hiển thị dữ liệu trên một trang web, nó thường cho người dùng nhập giá trị tìm kiếm của riêng họ.

Từ khi câu lệnh SQL chỉ là dạng text, nó trở nên dễ dàng hơn, với vài đoạn code máy tính, để tự động thay đổi câu lệnh SQL nhằm cung cấp cho người dùng lựa chọn dữ liệu:

Mã Server

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

Trong ví dụ trên, tạo một câu lệnh lựa chọn bằng cách thêm một biến (txtUserId) vào chuỗi lựa chọn. Các biến được lấy từ đầu vào người sử dụng (Request) đến trang.

Phần tiếp theo của bài viết này sẽ mô tả khả năng nguy hiểm của việc người dùng sử dụng các câu lệnh SQL.


SQL Injection

SQL injection là kỹ thuật của người dùng độc hại phá hoại cơ sở dữ liệu bằng cách thêm các dòng lệnh SQL inject vào câu lệnh SQL thông thường thông qua trường nhập liệu trên web.

Các dòng lệnh Inject SQL có thể thay đổi câu lệnh SQL và gây nguy hiểm cho khả năng bảo mật của ứng dụng web.


SQL Injection dựa trên 1=1 là luôn luôn đúng

Nhìn lên ví dụ trên một lần nữa.

Chúng ta biết rằng, mục đích ban đầu của code là tạo ra một câu lệnh SQL để chọn một người dùng với môt id người dùng cho trước.

Nếu không có gì để ngăn chặn người dùng nhập “sai”, người dùng có thể nhập vào dữ liệu “thông minh” như thế này:

UserId:

Kết quả của Server

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

Câu lệnh SQL trên là hợp lệ. Nó sẽ trả về tất cả các hàng từ bảng Users, vì WHERE 1=1 là luôn luôn đúng.

Ví dụ trên dường như nguy hiểm phải không? Điều gì xảy ra nếu bảng bao gồm tên và mật khẩu?

Câu lệnh SQL trên là tương đương với:

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

Một hacker thông minh có thể truy cập tất cả tên người dùng và mật khẩu trong cơ sở dữ liệu đơn giản bằng cách chèn 105 hoặc 1=1 vào trường nhập liệu.


SQL Injection dựa trên “”=”” là luôn luôn Đúng

Đây là một cấu trúc thống thường, được dùng để xác minh người dùng đăng nhập vào một trang web:

User Name:

Password:

Mã Server

uName = getRequestString("UserName");
uPass = getRequestString("UserPass"); sql = "SELECT * FROM Users WHERE Name ='" + uName + "' AND Pass ='" + uPass + "'"

Một hacker thông minh có thể truy cập tên người dùng và mật khẩu trong cơ sở dữ liệu bằng cách đơn giản chèn ” or “”=” vào ô tên người dùng hoặc mật khẩu.

Đoạn code tại server sẽ tạo ra một câu lệnh SQL hợp lệ giống như thế này:

Kết quả

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

Câu lệnh SQL là hợp lệ. Nó sẽ trả về tất cả các hàng từ bảng Users, vì WHERE “”=”” là luôn luôn đúng.


SQL Injection dựa trên câu lệnh SQL batched

Hầu hết các cơ sở dữ liệu hỗ trợ câu lệnh SQL batched, được cách nhau bằng dấu chấm phẩy.

Ví dụ

SELECT * FROM Users; DROP TABLE Suppliers

Câu lệnh SQL trên sẽ trả về tất cả các hàng trong bảng Users, và sau đó xoá bảng có tên là Suppliers.

Nếu chúng ta có đoạn mã server sau:

Server Code

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

Và nhập liệu như sau:

User id:

Đoạn code tại server sẽ tạo một lệnh SQL hợp lệ như sau:

Kết quả

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

Các tham số cho bảo vệ

Một số nhà phát triển web sử dụng một “danh sách đen” các từ hoặc ký tự để tìm kiếm khi nhập trong SQL, nhằm ngăn cản các thao tác tấn công của SQL injection.

Đây không phải là ý tưởng quá tốt. Nhiều từ trong số đó (như delete hoặc drop) và các ký tự (như dấu chấm phẩy và dấu ngoặc kép), là ngôn ngữ thường dùng, và phải được cho phép trong nhiều kiểu nhập liệu.

(Trong thực tế nó phải là hoàn toàn hợp lệ để nhập vào một câu lệnh SQL trong trường cơ sở dữ liệu.)

Cách chứng minh để bảo vệ một trang web từ các cuộc tấn công SQL injection, là sử dụng các tham số SQL.

Các tham số SQL là các giá trị được thêm vào từ các truy vấn SQL tại thời gian thực hiện, trong một cách thức có kiểm soát.

Ví dụ ASP.NET Razor

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

Lưu ý là tham số đại diện trong câu lệnh SQL bởi ký tự @.

Các công cụ SQL kiểm tra từng thông số để đảm bảo rằng nó là đúng cho cột và được thực thi theo nghĩa đen, và không phải là một phần của SQL được thực thi.

Ví dụ khác

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);

Bạn vừa được học để tránh SQL injection. Một trong những lỗ hổng website hàng đầu.

Các ví dụ

Các ví dụ dưới đây hiển thị cách làm thế nào để xây dựng các truy vấn tham số trong một số ngôn ngữ lập trình web phổ biến.

SELECT STATEMENT IN ASP.NET:
txtUserId = getRequestString("UserId");
sql = "SELECT * FROM Customers WHERE CustomerId = @0";
command = new SqlCommand(sql);
command.Parameters.AddWithValue("@0",txtUserID);
command.ExecuteReader();
INSERT INTO STATEMENT IN 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();
INSERT INTO STATEMENT IN 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();
Back to Top