SQL injection và cách phòng chống

                                 SQL injection và cách phòng chống
1. SQL injection
1.1 Định nghĩa:
SQL injection là một kỹ thuật cho phép những kẻ tấn công lợi dụng lỗ hổng của việc kiểm tra dữ liệu đầu vào trong các ứng dụng web và các thông báo lỗi của hệ quản trị cơ sở dữ liệu trả về để inject (tiêm vào) và thi hành các câu lệnh SQL bất hợp pháp. SQL injection có thể cho phép những kẻ tấn công thực hiện các thao tác, delete, insert, update,… trên cơ sở dữ liệu của ứng dụng, thậm chí là server mà ứng dụng đó đang chạy, 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ị cơ sở dữ liệu như SQL Server, MySQL, Oracle, DB2, Sysbase…
SQL Injection là một trong những lớp ứng dụng phổ biến nhất tại các cuộc tấn công đang được sử dụng trên Internet. Mặc dù thực tế rằng tương đối dễ dàng để chống lại SQL Injection, nhưng vẫn có số lượng lớn các trang web đối mặt với nguy cơ bị tấn công injection
Theo Web Application Security Consortium (WASC) 9% của tổng số sự cố hack báo cáo trong các phương tiện truyền thông cho đến ngày 27 tháng 7 2006 là do SQL Injection. Dữ liệu gần đây từ các nghiên cứu cho thấy rằng khoảng 50% của các trang web chúng tôi đã quét năm nay rất nhạy cảm với các lỗ hổng SQL Injection.
1.2 Các dạng lỗi thường gặp

Không kiểm tra ký tự thoát truy vấn
Đây là dạng lỗi SQL injection xảy ra khi thiếu đoạn mã kiểm tra dữ liệu đầu vào trong câu truy vấn SQL. Kết quả là người dùng cuối có thể thực hiện một số truy vấn không mong muốn đối với cơ sở dữ liệu của ứng dụng. Dòng mã sau sẽ minh họa lỗi này:
statement = “SELECT * FROM users WHERE name = ‘” + userName + “‘;”
Câu lệnh này được thiết kế để trả về các bản ghi tên người dùng cụ thể từ bảng những người dùng. Tuy nhiên, nếu biến “userName” được nhập chính xác theo một cách nào đó bởi người dùng ác ý, nó có thể trở thành một câu truy vấn SQL với mục đích khác hẳn so với mong muốn của tác giả đoạn mã trên. Ví dụ, ta nhập vào giá trị của biến userName như sau:
a’ or ‘t’=’t
Khiến câu truy vấn có thể được hiểu như sau:

SELECT * FROM users WHERE name = ‘a’ or ‘t’=’t';

Nếu đoạn mã trên được sử dụng trong một thủ tục xác thực thì ví dụ trên có thể được sử dụng để bắt buộc lựa chọn một tên người dùng hợp lệ bởi ‘t’=’t’ luôn đúng. Trong khi hầu hết các SQL server cho phép thực hiện nhiều truy vấn cùng lúc chỉ với một lần gọi, tuy nhiên một số SQL API như mysql_query của php lại không cho phép điều đó vì lý do bảo mật. Điều này chỉ ngăn cản tin tặc tấn công bằng cách sử dụng các câu lệnh riêng rẽ mà không ngăn cản tin tặc thay đổi các từ trong cú pháp truy vấn. Các giá trị của biến “userName” trong câu truy vấn dưới đây sẽ gây ra việc xoá những người dùng từ bảng người dùng cũng tương tự như việc xóa tất cả các dữ liệu được từ bảng dữ liệu (về bản chất là tiết lộ các thông tin của mọi người dùng), ví dụ này minh họa bằng một API cho phép thực hiện nhiều truy vấn cùng lúc:
a';DROP TABLE users; SELECT * FROM data WHERE ‘t’ = ‘t
Điều này đưa tới cú pháp cuối cùng của câu truy vấn trên như sau:
SELECT * FROM users WHERE name = ‘a';DROP TABLE users; SELECT * FROM data WHERE ‘t’ = ‘t';
Xử lý không đúng kiểu
Lỗi SQL injection dạng này thường xảy ra do lập trình viên hay người dùng định nghĩa đầu vào dữ liệu không rõ ràng hoặc thiếu bước kiểm tra và lọc kiểu dữ liệu đầu vào. Điều này có thể xảy ra khi một trường số được sử dụng trong truy vấn SQL nhưng lập trình viên lại thiếu bước kiểm tra dữ liệu đầu vào để xác minh kiểu của dữ liệu mà người dùng nhập vào có phải là số hay không. Ví dụ như sau:
statement:= “SELECT * FROM data WHERE id = ” + a_variable + “;”
Ta có thể nhận thấy một cách rõ ràng ý định của tác giả đoạn mã trên là nhập vào một số tương ứng với trường id – trường số. Tuy nhiên, người dùng cuối, thay vì nhập vào một số, họ có thể nhập vào một chuỗi ký tự, và do vậy có thể trở thành một câu truy vấn SQL hoàn chỉnh mới mà bỏ qua ký tự thoát. Ví dụ, ta thiết lập giá trị của biến a_variable là:
DROP TABLE users
khi đó, nó sẽ thực hiện thao tác xóa người dùng có id tương ứng khỏi cơ sở dữ liệu, vì câu truy vấn hoàn chỉnh đã được hiểu là:
SELECT * FROM data WHERE id=1;DROP TABLE users;
Lỗi bảo mật bên trong máy chủ cơ sở dữ liệu
Đôi khi lỗ hổng có thể tồn tại chính trong phần mềm máy chủ cơ sở dữ liệu, như là trường hợp hàm mysql_real_escape_string() của các máy chủ MySQL. Điều này sẽ cho phép kẻ tấn công có thể thực hiện một cuộc tấn công SQL injection thành công dựa trên những ký tự Unicode không thông thường ngay cả khi đầu nhập vào đang được thoát
Blind SQL injection
Lỗi SQL injection dạng này là dạng lỗi tồn tại ngay trong ứng dụng web nhưng hậu quả của chúng lại không hiển thị trực quan cho những kẻ tấn công. Nó có thể gây ra sự sai khác khi hiển thị nội dung của một trang chứa lỗi bảo mật này, hậu quả của sự tấn công SQL injection dạng này khiến cho lập trình viên hay người dùng phải mất rất nhiều thời gian để phục hồi chính xác từng bit dữ liệu. Những kẻ tấn công còn có thể sử dụng một số công cụ để dò tìm lỗi dạng này và tấn công với những thông tin đã được thiết lập sẵn.
Thay đổi giá trị điều kiện truy vấn
Dạng lỗi này khiến cho kẻ tấn công có thể thay đổi giá trị điều kiện trong câu truy vấn, làm sai lệch sự hiển thị của một ứng dụng chứa lỗi này.
SELECT booktitle from booklist where bookId = ‘OOk14cd’ AND 1=1;
Sẽ hiển thị một trang một cách bình thường, trong khi:
SELECT booktitle from booklist where bookId = ‘OOk14cd’ AND 1=2;
sẽ hiển thị một nội dung khác, hoặc không hiển thị gì nếu ứng dụng web có chứa lỗi SQL injection dạng này. Lỗ hổng dạng này còn cho phép tin tặc không chỉ gây ảnh hưởng tới bảng hay dữ liệu hiện tại mà còn ảnh hưởng tới những dữ liệu hay bảng khác phụ thuộc vào nội dung của dữ liệu hay bảng hiện tại.
Điều kiện lỗi
Lỗi SQL injection dạng này dẫn tới việc buộc cơ sở dữ liệu chỉ được phép đánh giá khi mà giá trị của câu lệnh WHERE là đúng. Ví dụ:
SELECT 1/0 from users where username=’Ralph';
Phép chia cho 0 chỉ được đánh giá là lỗi khi mà người dùng có tên “Ralph” tồn tại trong cơ sở dữ liệu.
Thời gian trễ
Lỗi SQL injection dạng này tồn tại khi thời gian xử lý của một hay nhiều truy vấn SQL phụ thuộc vào dữ liệu logic được nhập vào hoặc quá trình xử lý truy vấn của SQL engine cần nhiều thời gian. Tin tặc có thể sử dụng lỗi SQL injection dạng này để xác định thời gian chính xác mà trang cần tải khi giá trị nhập vào là đúng.
Một số dạng tấn công thường gặp với các ứng dụng web
Có bốn dạng tấn công thường gặp bao gồm: vượt qua kiểm tra lúc đăng nhập, sử dụng câu lệnh SELECT, sử dụng câu lệnh INSERT, sử dụng các stored-procedures.
Dạng tấn công vượt qua kiểm tra lúc đăng nhập
Với dạng tấn công này, tin tặc có thể dễ dàng vượt qua các trang đăng nhập nhờ vào 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. 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. Ví dụ, trong trường hợp sử dụng ASP, người ta có thể dùng 2 trang: 1 trang HTML để hiển thị Form nhập liệu và 1 trang ASP để xử lý thông tin nhập vào từ phía người dùng như sau:
– Trang nhập liệu: login.htm

 

Username:

Password:

– Trang xử lý nhập liệu: execlogin.asp

Chỗ sơ hở trong đoạn mã xử lý nhập liệu trên nằm ở chỗ dữ liệu nhập vào từ người dùng được dùng để xây dựng trực tiếp câu lệnh SQL. Chính điều này cho phép tin tặc có thể điều khiển câu truy vấn sẽ được thực hiện. Ví dụ, nếu người dùng nhập chuỗi trong ngoặc sau vào trong cả 2 ô nhập liệu username/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
Dạng tấn công này phức tạp hơn. Để thực hiện được kiểu tấn công này, kẻ tấn công phải có khả năng hiểu và lợi dụng các sơ hở trong các thông báo lỗi từ hệ thống để dò tìm các điểm yếu khởi đầu cho việc tấn công. Ví dụ, trong các trang tìm kiếm. Các trang này cho phép người dùng nhập vào các thông tin tìm kiếm như Họ, Tên, … Đoạn mã thường gặp là:

Tương tự như trên, tin tặc có thể lợi dụng sơ hở trong câu truy vấn SQL để nhập vào trường tên tác giả bằng chuỗi 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. Giả sử đoạn mã nhập vào là:
‘ DROP TABLE T_AUTHORS –
Câu truy vấn sẽ thực hiện việc xóa bảng.
Dạng tấn công sử dụng câu lệnh INSERT
Thông thường các ứng dụng web cho phép người dùng đăng kí một tài khoản để tham gia. Chức năng không thể thiếu là sau khi đăng kí thành công, người dùng có thể xem và hiệu chỉnh thông tin của mình. SQL injection có thể được dùng khi hệ thống không kiểm tra tính hợp lệ của thông tin nhập vào. Ví dụ, một câu lệnh INSERT có thể có cú pháp dạng:
INSERT INTO TableName VALUES(‘Value One’, ‘Value Two’, ‘Value Three’)
Nếu đoạn mã xây dựng câu lệnh SQL có dạng:

Thì chắc chắn sẽ bị lỗi SQLi, bởi vì nếu ta nhập vào trường thứ nhất ví dụ như:
‘ + (SELECT TOP 1 FieldName FROM TableName) + ‘
Lúc này câu truy vấn sẽ là:
INSERT INTO TableName VALUES(‘ ‘ + (SELECT TOP 1 FieldName FROM TableName) + ‘ ‘, ‘abc’, ‘def’)
Khi đó, lúc thực hiện lệnh xem thông tin, xem như bạn đã yêu cầu thực hiện thêm một lệnh nữa đó là:
SELECT TOP 1 FieldName FROM TableName
Dạng tấn công sử dụng stored-procedures
Việc tấn công bằng stored-procedures sẽ gây tác hại rất lớn nếu ứng dụng được thực thi với quyền quản trị hệ thống ‘sa’. Ví dụ, nếu ta thay đoạn mã tiêm vào dạng: ‘; EXEC xp_cmdshell ‘cmdd.exe dir C: ‘. Lúc này hệ thống sẽ thực hiện lệnh liệt kê thư mục trên ổ đĩa C:\ cài đặt server. Việc phá hoại kiểu nào tuỳ thuộc vào câu lệnh đằng sau cmd.exe.
2. Tác Hại Và Cách Phòng Chống
2.1 Tác hại
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.
Tuy diễn ra âm thầm nhưng thiệt hại của những vụ tấn công này lại rất lớn. Nếu như một máy chủ cơ sở dữ liệu bị tin tặc chiếm quyền kiểm soát thì sẽ có một khối lượng rất lớn thông tin cá nhân tài chính của người dùng sẽ rơi vào tay chúng. Và nếu thành công thì có thể nói nguồn thông tin mà tin tặc thu được còn nhiều hơn rất nhiều so với tấn công phishing. Tin tặc không phải mất công giả mạo để lừa người sử dụng cung cấp thông tin cá nhân tài chính. Tỉ lệ thành công của các vụ tấn công SQL Injection thường rất cao.
Một trong những vụ tấn công SQL Injection nổi tiếng nhất chính là vụ tấn công vào CardSystems Solutions – một hãng chuyên lưu trữ có sở dữ liệu thanh toán thẻ tín dụng. Tin tặc đã sử dụng giải pháp tấn công SQL Injection để chiếm quyền điều khiển hệ thống cơ sở dữ liệu của CardSystems và chuyển toàn bộ cơ sở dữ liệu ra ngoài. Đã có khoảng 40 triệu thẻ tín dụng rơi vào tay chúng gây ra thiệt hại hàng triệu USD.
2.2 Cách phòng chống
Để 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.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">