SQL injection
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 5.Tóm tắt
Trang tra cứu đơn hàng cho khách nhập email. Code ghép chuỗi email đó vào câu SQL rồi chạy. Một người gõ vào ô email một đoạn SQL thay vì email, và thế là họ đọc được thông tin của mọi khách. Đó là SQL injection, một lỗi bảo mật rất phổ biến.
Khái niệm
🧨 SQL injection: kiểu tấn công chèn đoạn SQL vào dữ liệu người dùng nhập, khiến câu lệnh làm việc khác với ý định.
🧷 Bind variable (tham số): chỗ giữ trong câu SQL như :email, giá trị được gửi riêng nên Oracle luôn coi là dữ liệu, không bao giờ coi là code SQL.
Ví dụ
Code C# ghép chuỗi:
// SAI — ghép thẳng dữ liệu người dùng vào SQL
string sql =
"SELECT name FROM customers WHERE email = '"
+ email + "'";Viết bằng $"... '{email}'" (string interpolation ở khoá C# Core) cũng là
ghép chuỗi, nguy hiểm y hệt. Người dùng nhập ' OR '1'='1, câu SQL thành:
-- SAI — điều kiện luôn đúng
SELECT name FROM customers
WHERE email = '' OR '1'='1';Dùng bind variable với thư viện Oracle.ManagedDataAccess.Core:
// ĐÚNG — email được gửi riêng, không ghép vào SQL
using Oracle.ManagedDataAccess.Client;
var cmd = new OracleCommand(
"SELECT name FROM customers WHERE email = :email",
conn);
cmd.Parameters.Add(new OracleParameter("email", email));conn là kết nối đã mở tới Oracle. Đoạn C# này chỉ để đọc hiểu; muốn chạy
thật thì cần package NuGet Oracle.ManagedDataAccess.Core.
:emaillà chỗ giữ, giá trị thật truyền quaParameters.- Người dùng gõ gì vào ô email thì Oracle cũng chỉ coi đó là một chuỗi để so sánh.
- Bind variable còn giúp Oracle dùng lại cách chạy đã tính cho câu SQL đó khi chỉ có giá trị thay đổi, nên nhanh hơn.
Thử ngay
Chạy thử câu SQL mà kẻ tấn công tạo ra:
SELECT name
FROM customers
WHERE email = '' OR '1'='1'
ORDER BY customer_id;Đoán trước khi chạy: không ai có email rỗng. Câu này trả về mấy khách?
Xem kết quả
| NAME |
|---|
| An |
| Bình |
| Chi |
| Dũng |
Cả bốn khách. '1'='1' luôn đúng, nối bằng OR nên điều kiện đúng với mọi
dòng. Thông tin của mọi khách bị lộ chỉ vì một ô nhập liệu.
Lỗi hay gặp
Ghép chuỗi vì "dữ liệu này an toàn". Hôm nay giá trị đến từ code, mai có người đổi thành lấy từ ô nhập liệu. Luôn dùng bind variable cho mọi giá trị đưa vào SQL.
Tự lọc dấu nháy thay vì dùng tham số. Tự thay ' bằng '' chặn được ví
dụ trên, nhưng dễ quên ở một chỗ nào đó, và không giúp gì khi giá trị ghép vào
không nằm trong nháy, như một con số.
// SAI — tự "làm sạch" vẫn là ghép chuỗi
string safe = email.Replace("'", "''");
string sql =
"SELECT name FROM customers WHERE email = '"
+ safe + "'";// ĐÚNG — không tự thay dấu nháy, dùng tham số
using Oracle.ManagedDataAccess.Client;
var cmd = new OracleCommand(
"SELECT name FROM customers WHERE email = :email",
conn);
cmd.Parameters.Add(new OracleParameter("email", email));Bind variable tách hẳn dữ liệu khỏi code SQL, nên không cần tự lọc gì.
Tóm tắt
- SQL injection xảy ra khi dữ liệu người dùng được ghép thẳng vào câu SQL.
- Kẻ tấn công chèn đoạn như
' OR '1'='1để đổi ý nghĩa câu lệnh. - Dùng bind variable (
:ten) cho mọi giá trị, không tự ghép chuỗi. - Tự lọc dấu nháy không thay được bind variable.
Tự kiểm tra
0/3 câuCâu SQL nào an toàn trước SQL injection?
Ô tìm kiếm ghép thẳng vào SQL. Người dùng nhập ' OR '1'='1. Chuyện gì xảy ra?
Ngoài chặn SQL injection, bind variable còn giúp gì?