17/09/2018, 16:57

Chống tấn công SQL Injection cho website

Việc thiết kế và đưa website vào hoạt động luôn đòi hỏi các nhà phát triển phải quan tâm đến vấn đề về an toàn, bảo mật nhằm giảm thiểu tối đa khả năng bị tin tặc tấn công. Thường các nhà phát triển tập trung vào các vấn đề an toàn của hệ điều hành, hệ quản trị CSDL, webserver… Chẳng hạn ...

Việc thiết kế và đưa website vào hoạt động luôn đòi hỏi các nhà phát triển phải quan tâm đến vấn đề về an toàn, bảo mật nhằm giảm thiểu tối đa khả năng bị tin tặc tấn công. Thường các nhà phát triển tập trung vào các vấn đề an toàn của hệ điều hành, hệ quản trị CSDL, webserver… Chẳng hạn như hổng bảo mật trên IIS. Tuy nhiên, có một nguy cơ tiềm ẩn ít được quan tâm đó là các đoạn mã của ứng dụng. Một trong số đó là tấn công SQL Injection.

Tấn công Sql injection là gì?

SQL Injection là một kĩ thuật cho phép những kẻ tấn công thi hành các câu lệnh truy vấn SQL bất hợp pháp (người phát triển không lường trước được) bằng cách lợi dụng lỗ hổng trong việc kiểm tra dữ liệu nhập từ các ứng dụng web. Hậu quả này rất tai hại vì nó cho phép kẻ tấn công có toàn quyền, hiệu chỉnh… trên cơ sở dữ liệu của ứng dụng. Lỗi này thường xảy ra trên các ứng dụng web có dữ liệu được quản lí bằng các hệ quản trị CSDL như SQL Server, Oracle, DB2, Sysbase.

Xét một ví dụ điển hình, thông thường để cho phép người dùng truy cập vào các trang web được bảo 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 vào, hệ thống sẽ kiểm tra tên đăng nhập và mật khẩu có hợp lệ hay không để quyết định cho phép hay từ chối thực hiện tiếp.

Trong trường hợp này, người ta có thể dùng 2 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ụ:

Login.htm

<form action=”ExecLogin.asp” method=”post”>

Username:  <input type=”text” name=”txtUsername”><br>

Password:  <input type=”password” name=”txtPassword”><br>

<input type=”submit”>

</form>

ExecLogin.asp

<%

Dim p_strUsername, p_strPassword, objRS, strSQL

p_strUsername = Request.Form(“txtUsername”)

p_strPassword = Request.Form(“txtPassword”)

strSQL = “SELECT * FROM tblUsers “ & _ “WHERE Username=’”

& _strUsername & _

“‘ and Password=’” & p_strPassword & “‘“

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(“Username”)

End If

Set objRS = Nothing

%>

Thoạt nhìn, đoạn mã trong trang ExecLogin.asp dường như không chứa bất cứ một lỗ hổng bảo mật 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 tấn công SQL Injection. Đặc biệt, sơ hở nằm ở chỗ dữ liệu người dùng nhập vào được dùng để xây dựng trực tiếp câu lệnh truy vấn SQL. Chính điều này cho phép những kẻ tấn công có thể điều khiển được câu truy vấn sẽ được thực hiện.

Ví dụ, nếu người dùng nhập chuỗi sau vào trong cả 2 ô nhập liệu username/password của trang Login.htm:

‘ or ‘’ = ‘ . Lúc này, câu truy vấn sẽ được gọi thực hiện là:

SELECT * FROM tblUsers WHERE Username=’’ or ‘’=’’ and 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 tblUsers, 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ệ.

Một ví dụ khác của tấn công SQL Injection nữa là khi các trang Web sử dụng dữ liệu nhập vào theo dạng querystring (bằng cách gõ cặp tham số và giá trị trực tiếp trên thanh địa chỉ hoặc dùng form với thuộc tính ACTION là GET). Ví dụ sau minh họa một trang ASP nhận dữ liệu cho biến ID thông qua querystring và phát sinh nội dung của trang đó dựa trên ID:

<%

Dim p_lngID, objRS, strSQL

p_lngID = Request(“ID”)

strSQL = “SELECT * FROM tblArticles WHERE ID=” & p_lngID

Set objRS = Server.CreateObject(“ADODB.Recordset”)

objRS.Open strSQL, “DSN=…”

If (Not objRS.EOF) Then Response.Write objRS(“ArticleContent”)

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 article có ID trùng với ID được chuyển đến cho nó dưới dạng querystring. Ví dụ, trang này có thể được gọi như sau:

http://www.example.com/Article.asp?ID=1055, để hiển thị nội dung của article có ID là 1055.

Giống như ví dụ đăng nhập ở trên, đoạn mã này để lộ sơ hở cho khả năng tấn công SQL Injection. Kẻ tấn công có thể thay thế một ID hợp lệ bằng cách gán ID cho một giá trị khác, để thực hiện một lệnh SQL bất hợp pháp,  ví dụ như: 0 or 1=1 (nghĩa là, http://www.example.com/Article.asp?ID=0 or 1=1).

Câu truy vấn SQL lúc này sẽ trả về tất cả các article từ bảng dữ liệu vì nó sẽ thực hiện câu lệnh:

SELECT * FROM tblArticles WHERE ID=0 or 1=1

Tất nhiên ví dụ này dường như không có gì nguy hiểm, nhưng hãy thử tưởng tượng kẻ tấn công có thể xóa toàn bộ CSDL bằng cách chèn vào các đoạn lệnh nguy hiểm như lệnh DELETE. Tất cả chỉ là đơn giản thay đổi chuỗi gán dữ liệu cho ID, ví dụ như:

http://www.example.com/Article.asp?ID=1055; DELETE FROM tblArticles.

Tác hại và phòng tránh tấn công SQL Injection

Tác hại của dạng tấn công 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 CSDL) 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ệ CSDL và thậm chí 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 các nguy cơ có thể xảy ra, hãy bảo vệ các câu truy vấn SQL bằng cách kiểm soát chặt chẽ tất cả các dữ liệu nhập nhận được từ đối tượng Request (Request, Request. QueryString, Request.Form, Request. Cookies, và Request.Server Variables).

Trong trường hợp dữ liệu nhập vào là chuỗi, như trong ví dụ 1, lỗi xuất phát từ việc có dấu nháy đơn trong dữ liệu. Để tránh điều này, thay thế các dấu nháy đơn bằng hàm Replace để thay thế bằng 2 dấu nháy đơn:

p_strUsername = Replace(Request.Form(“txtUsername”), “‘“, “‘’”)

p_strPassword = Replace(Request.Form(“txtPassword”), “‘“, “‘’”)

Trong trường hợp dữ liệu nhập vào là số, như trong ví dụ 2, 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:

p_lngID = CLng(Request(“ID”))

Như vậy, nếu người dùng truyền vào một chuỗi, hàm này sẽ trả về lỗi ngay lập tức. Ngoài ra để tránh các nguy cơ từ tấn công SQL Injection, nên chú ý loại bỏ bất kì thông tin kĩ thuật nào chứa trong thông điệp chuyển tới cho người dùng khi ứng dụng có lỗi. Các thông báo lỗi thông thường tiết lộ các chi tiết kĩ thuật có thể cho phép kẻ tấn công biết được điểm yếu của hệ thống.

Bạn có thể tham khảo thêm thông tin về cách thức tạo ra các trang báo lỗi tùy ý trong “Tạo ra các trang báo lỗi ASP được tùy biến”.

Cuối cùng, để hạn chế thiệt hại do tấn công SQL Injection, nên kiểm soát chặt chẽ và giới hạn quyền xử lí dữ liệu của tài khoản người dùng mà ứng dụng web đang sử dụng. Các ứng dụng thông thường nên tránh dùng các quyền như dbo hay sa. Quyền càng hạn chế, thiệt hại càng ít.

0