SQL Injection là gì
Khi thiết kế và triển khai hệ thống website trên Internet, nhiều khi người lập trình vẫn nghĩ rằng bảo đảm an ninh và bảo mật để giảm thiểu khả năng tấn công của hacker là các vấn đề như: như chọn hệ điều hành, quản lý cơ sở dữ liệu, máy chủ web sẽ chạy ứng dụng... nhưng ngay cả bản thân website đó cũng có thể có một lỗ hổng bảo mật lớn. Một trong những lỗ hổng này là SQL Injection.
SQL injection có thể hiểu là một cách tấn công, khi đó những kẻ tấn công lợi dụng lỗ hổng khi xử lý dữ liệu nhập trong các trang web để "tiêm vào" (inject) các câu lênh SQL bất hợp pháp và thi hành các câu lệnh đó.
Hậu quả của việc này thường rất nghiêm trọng vì những kẻ tấn công có thể dựa vào đó thực hiện các câu lệnh thêm, sửa, xóa... trên cơ sở dữ liệu
Các dạng tấn công bằng SQL Injection
SQL Injection có 4 dạng tấn công thường gặp, đó là: sử dụng câu lệnh INSERT, sử dụng câu lệnh SELECT, vượt qua kiểm tra lúc đăng nhập, sử dụng các stored-procedures.
+ Dạng tấn công vượt qua kiểm tra đăng nhập:
Đây là dạng tấn công mà tin tặc có thể vượt qua các trang đăng nhập, làm được điều này nhờ vào việc khai thác lỗi khi dùng các câu lệnh SQL thao tác trên cơ sở dữ liệu của ứng dụng web.
Một ví dụ điển hình, thông thường khi cho phép người dùng truy cập vào các trang web được bảo mật, một hệ thống thường xây dựng trang đăng nhập để yêu cầu người dùng nhập thông tin về tên đăng nhập và mật khẩu. Sau khi người dùng nhập thông tin, hệ thống sẽ tiến hành kiểm tra tên đăng nhập cùng với mật khẩu có hợp lệ hay không để quyết định cho phép thực hiện tiếp hay không. Trong trường hợp này, người ta có thể dùng hai trang, một trang HTML để hiển thị form nhập liệu và một trang ASP dùng để xử lí thông tin nhập từ phía người dùng.
Ví dụ:
CODE
<%
Dim vUsrName, vPassword, objRS, strSQL
vUsrName = Request.Form("fUSRNAME")
vPassword = Request.Form("fPASSWORD")
strSQL = "SELECT * FROM T_USERS " & _
"WHERE USR_NAME=' " & vUsrName & _
" ' and USR_PASSWORD=' " & vPassword & " ' "
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
If (objRS.EOF) Then
Response.Write "Invalid login."
Else
Response.Write "You are logged in as " & objRS("USR_NAME")
End If Set objRS = Nothing %>
Thoạt nhìn, đoạn mã dường như không chứa bất cứ một lỗ hổng về an toàn nào. Người dùng không thể đăng nhập mà không có tên đăng nhập và mật khẩu hợp lệ. Tuy nhiên, đoạn mã này thực sự không an toàn và là tiền đề cho một lỗi SQL injection. Chính điều này đã cho phép những kẻ tấn công có thể điều khiển câu truy vấn tiếp theo sẽ được thực hiện. Ví dụ, nếu nhập chuỗi sau vào trong ô nhập liệu username và password của trang login.htm là:
' OR ' ' = ' '. Lúc này, câu truy vấn sẽ được gọi thực hiện là:
SELECT * FROM T_USERS WHERE USR_NAME ='' OR ''='' and
USR_PASSWORD= '' OR ''=''
Câu truy vấn này là hợp lệ và sẽ trả về tất cả các bản ghi của T_USERS và đoạn mã tiếp theo xử lí người dùng đăng nhập bất hợp pháp này như là người dùng đăng nhập hợp lệ.
+ Dạng tấn công sử dụng câu lệnh SELECT:
Đây là dạng tấn công phức tạp, kẻ tấn công thường có kiến thức về cơ sở dữ liệu và có khả năng tìm ra các sơ hở trong thông báo lỗi của hệ thống, từ đó làm tiền đề để tấn công. Xét một ví dụ rất thường gặp trong các website về tin tức. Thông thường, sẽ có một trang nhận ID của tin cần hiển thị rồi sau đó truy vấn nội dung của tin có ID này. Mã nguồn cho chức năng này thường được viết khá đơn giản theo dạng.
CODE
<%
Dim vNewsID, objRS, strSQL
vNewsID = Request("ID")
strSQL = "SELECT * FROM TNEWS WHERE NEWS_ID =" &
vNewsID 3
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
Set objRS = Nothing
%>
Trong các tình huống thông thường, đoạn mã này hiển thị nội dung của tin có ID trùng với ID đã chỉ định và hầu như không thấy có lỗi. Tuy nhiên, giống như ví dụ đăng nhập ở trước, đoạn mã này để lộ sơ hở cho một lỗi SQL injection khác.
Kẻ tấn công có thể thay thế ID mặc định bằng cách gán một giá trị khác cho ID đó, đó là cách khởi đầu cuộc tấn công, ví dụ như: abc OR 1=1, câu lệnh truy vấn SQL lúc này sẽ là câu lệnh tìm kiếm tất cả từ bảng dữ liệu vì nó sẽ có dạng:
SELECT * FROM T_NEWS WHERE NEWS_ID=abc or 1=1
Một trường hợp khác, ví dụ như trang tìm kiếm, đây là trang cho phép người dùng tìm kiếm các thông tin như họ, tên, ngày sinh..., ví dụ:
CODE
<%
Dim vAuthorName, objRS, strSQL
vAuthorName = Request("fAUTHOR_NAME")
strSQL = "SELECT * FROM TAUTHORS WHERE
AUTHOR_NAME =' " & _
vAuthorName & " ' "
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
…
Set objRS = Nothing
%>
Nếu trang tìm kiếm sử dụng đoạn mã trên, kẻ tấn công có thể tìm ra sơ hở và nhập vào ô tên giá trị:
' UNION SELECT ALL SELECT OtherField FROM OtherTable
WHERE ' '='
Lúc này, ngoài câu truy vấn đầu không thành công, chương trình sẽ thực hiện thêm lệnh tiếp theo sau từ khóa UNION nữa. Tất nhiên các ví dụ nói trên, dường như không có gì nguy hiểm, nhưng kẻ tấn công có thể xóa toàn bộ cơ sở dữ liệu bằng cách chèn vào các đoạn lệnh nguy hiểm như lệnh DROP TABLE.
+ Dạng tấn công sử dụng câu lệnh INSERT:
Các ứng dụng trên web muốn lưu thông tin người sử dụng thường có chức năng tạo tài khoảng cho người dùng, người dùng có thể đăng ký thông tin khi tạo tài khoản hoặc điều chỉnh sau khi đăng ký thành công. Trong những việc này, kẻ tấn công cũng có thể lợi dụng để tấn công SQL injection khi mà hệ thống bỏ qua việc kiểm tra tính hợp lệ của thông tin nhập vào. Ví dụ, với một câu lệnh INSERT có cú pháp: INSERT INTO Table_Name VALUES('V1, 'V2', 'V3').
Nếu đoạn mã có dạng:
CODE
<%
strSQL = "INSERT INTO TableName VALUES(' " & strV1
& " ', ' " _ & strV2 & " ', ' " & strV3 & " ') "
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
…
Set objRS = Nothing
%>
Thì sẽ bị lỗi SQL injection, để chứng minh điề này, trong trường thứ nhất ta nhập: ' + (SELECT TOP 3 FieldName FROM Table_Name) + '. Khi này máy sẽ thực hiện câu lệnh truy vấn: INSERT INTO TableName VALUES(' ' + (SELECT TOP 3 FieldName FROM Table_Name) + ' ', 'aaaa', 'bbbbb'). Kết quả nhận được ngoài lệnh xem thông tin, máy còn thực hiện một lệnh nữa đó là: SELECT TOP 3 FieldName FROM Table_Name.
Cách phòng chống tấn công SQL
Như vậy, có thể thấy lỗi SQL injection khai thác những bất cẩn của các lập trình viên phát triển ứng dụng web khi xử lí các dữ liệu nhập vào để xây dựng câu lệnh SQL. Tác hại từ lỗi SQL injection tùy thuộc vào môi trường và cách cấu hình hệ thống. Nếu ứng dụng sử dụng quyền dbo (quyền của người sở hữu cơ sở dữ liệu - owner) khi thao tác dữ liệu, nó có thể xóa toàn bộ các bảng dữ liệu, tạo các bảng dữ liệu mới, … Nếu ứng dụng sử dụng quyền sa (quyền quản trị hệ thống), nó có thể điều khiển toàn bộ hệ quản trị cơ sở dữ liệu và với quyền hạn rộng lớn như vậy nó có thể tạo ra các tài khoản người dùng bất hợp pháp để điều khiển hệ thống của bạn. Để phòng tránh, ta có thể thực hiện ở hai mức:
- Kiểm soát chặt chẽ dữ liệu nhập vào.
Chúng ta có thể kiểm soát chặt chẽ dữ liệu nhập vào bằng cách bảo vệ các câu lệnh SQL như kiểm soát chặt chẽ tất cả các dữ liệu nhập nhận được từ các đối tượng Request (Request, Request.QueryString, Request.Cookies, Request.Form, Request.ServerVariables). Ví dụ, ta có thể giới hạn chiều dài của chuỗi nhập liệu, hoặc xây dựng hàm EscapeQuotes để thay thế các dấu nháy đơn bằng 2 dấu nháy đơn như:
CODE
<%
Function EscapeQuotes(sInput)
sInput = replace(sInput, " ' ", " ' ' ")
EscapeQuotes = sInput
End Function
%>
Trong trường hợp dữ liệu nhập vào là số, lỗi xuất phát từ việc thay thế một giá trị được tiên đoán là dữ liệu số bằng chuỗi chứa câu lệnh SQL bất hợp pháp. Để tránh điều này, đơn giản hãy kiểm tra dữ liệu có đúng kiểu hay không bằng hàm IsNumeric(). Ngoài ra có thể xây dựng hàm loại bỏ một số kí tự và từ khóa nguy hiểm như: ;, --, select, insert, xp_, … ra khỏi chuỗi dữ liệu nhập từ phía người dùng để hạn chế các tấn công dạng này:
CODE
<%
Function KillChars(sInput)
dim badChars
dim newChars
badChars = array("select", "drop", ";", "--", "insert", "delete",
"xp_")
newChars = strInput
for i = 0 to uBound(badChars)
newChars = replace(newChars, badChars(i), "")
next
KillChars = newChars
End Function
%>
» Các tin khác: