Tìm kiếm trong Blog này

Thứ Ba, 24 tháng 4, 2012

Hướng Dẫn Kết Nối Cơ Sở Dữ Liệu Trên C-Sharp (C#) Bằng MS-Sql Server 2005 part 1

Trước tiên để kết nối cơ sở dữ liệu (CSDL) bạn cần có công cụ C# và MS-Sql 2005
hình 1
Sau khi cài đặt thành công C# và Sql Server ta cần xác định thông tin cần thiết để tiến hành kết nối CSDL
hình 2
Thông tin cần quan tâm ở đây là: 
- Server name: "EMCHINES-PC\SQLEXPRESS" or ".\SQLEXPRESS"
- Login: "sa" (default)
- Password: ở đây lấy ví dụ là "admin"
- Tên CSDL:  " EXECISE" (hình 3)

hình 3

Sau khi có đầy đủ thông tin ta bắt đầu lập trình
Tất cả các câu lệnh cần thiết để thiết lập kết nối đều nằm trong thư viện: "System.Data.SqlClient"
using System.Data.SqlClient;
public class Connection
    {
//Khai báo các biến cho kết nối:
        public static SqlConnection sqlConnection; //dùng để tạo kết nối
        public static SqlCommand sqlCommand; // dùng thực thi câu lệnh sql
        public static SqlDataAdapter sqlDataAdapter;
        public static SqlDataReader sqlDataReader;

//Khai báo chuỗi kết nối với thông tin đã được xác định trước đó
        public static String sqlConn = "Server= EMCHINES-PC\\SQLEXPRESS      
; Database=EXECISE ; uid = sa ; pwd = admin";
        
//Tạo hàm mở kết nối
        public static void OpenConnect()
        {
            try
            {
                sqlConnection = new SqlConnection(sqlConn);
                sqlConnection.Open(); //Mở kết nối
            }
            catch (Exception ex) //Bắt ngoại lệ nếu có
            {
                MessageBox.Show("Lỗi kết nối "+ex.Message);
            }
        }

        //Đóng kết nối
        public static void CloseConnect()
        {
            try
            {
                sqlConnection.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Lỗi đóng kết nối!!");
            }
        }

        //Thực thi câu lệnh sql và trả về một bảng dữ liệu từ Database
        public static DataSet FillDataSet(String sqlQuery)
        {
            DataSet dataSet = new DataSet();
            try
            {
                //OpenConnect();
                sqlDataAdapter = new SqlDataAdapter(sqlQuery, sqlConnection);
                sqlDataAdapter.Fill(dataSet);
                sqlDataAdapter.Dispose();
            }
            catch
            {
                MessageBox.Show("Lỗi thực thi!!");
            }
            finally
            {
                CloseConnect();                
            }
            return dataSet;
        }

        //Thực thi câu lệnh sql và trả về một phần dữ liệu của database ( chỉ được đọc 1 lần/ tăng tốc độ)
        public static SqlDataReader FillDataReader(String sqlQuery)
        {
            try
            {
                //OpenConnect();
                sqlCommand=new SqlCommand();
                sqlCommand.Connection = sqlConnection;
                sqlCommand.CommandText = sqlQuery;
                sqlDataReader = sqlCommand.ExecuteReader();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Lỗi thực thi!!!");
            }
            finally
            {
                //CloseConnect();
                sqlCommand.Dispose();
            }
            return sqlDataReader;
        }

        //Thực thi câu lệnh sql và không trả về kết quả nào thường dùng cho Update và Delete dữ liệu trong //bảng
        public static bool ExecuteNonReturn(String sqlQuery)
        {
            try
            {
                //OpenConnect();
                sqlCommand = new SqlCommand();
                sqlCommand.Connection = sqlConnection;
                sqlCommand.CommandText = sqlQuery;
                sqlCommand.ExecuteNonQuery();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Lỗi thực thi câu lệnh!!");
                return false;
            }
            finally
            {
                //CloseConnect();
                sqlCommand.Dispose();
            }
        }

        //Đóng kết nối DataReader
        public static void CloseDataReader()
        {
            try
            {
                sqlDataReader.Close();
            }
            catch (Exception ex)
            {
            }
        }
    }


Bây giờ ta sẽ đi vào 1 ví dụ cụ thể:

Ta có một CSDL với 1 bảng có sẳn ( có thể tự thêm dữ liệu vào để xem kết quả chính xác hơn)


//Kết thúc Part 1

Thứ Bảy, 10 tháng 9, 2011

Cách tấn công một trang web bằng SQL-INJECTION. Tác hại và cách phòng tránh-Phần 1

1. Các dạng tấn công bằng SQL-injection:

Có bốn dạng thông thường bao gồm: vượt qua kiểm tra lúc đăng nhập (authorization bypass), sử dụng câu lệnh SELECT, sử dụng câu lệnh INSERT và sử dụng các stored-procedures.

1.1 Tấn công bằng cách 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.
Xét một ví dụ: thông thường để cho phép người dùng đăng nhập vào một trang web được bảo mật, hệ thống thường xây dựng một trang web đăng nhập yêu cầu người dùng nhập thông tin về username và password. Sau khi người dùng nhập thông tin vào, hệ thống sẽ kiểm tra username và password có hợp lệ hay không để quyết định dừng lại hay thực hiện tiếp. Trong trường hợp này người ta có thể dùng 2 trang, 1 trang HTML dùng để hiển thì form nhập liệu, 1 trang ASP dùng để xử lí thông tin nhập từ phía người dùng. Ví dụ:

login.html
Username:
Password:
execlogin.asp
<% 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ã trong execlogin.asp dường như không hề chứa một lỗ hỗng về an toàn nào. Người dùng không thể đăng nhập nếu 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à một tiền đề cho một lỗi SQL injection. Ví dụ nếu người dùng nhập chuỗi ' OR ' ' =' ' vào 2 ô nhập liệu username và password . Lúc này câu truy vấn đượ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 hoàn toàn hợp lệ và sẽ trã lại toàn bộ các bản ghi trong bảng T_USERS và đoạn mã tiếp theo sẽ xử lý người dùng đăng nhập bất hợp pháp này như là người dùng hợp lệ.

1.2 Tấn công sử dụng câu lệnh Select

Dạng tấn công này khá phức tạp. Để sử dụng được kiểu tấn công này, kẻ tấn công phải có khả năng hiểu và sử dụng sơ hở trong các thông báo lỗi từ hệ thống để dò tìm các yếu điểm khởi đầu cho việc tấn công.
Xét một ví dụ thường gặp ở các trang tin tức. Thông thường sẽ có một trang nhập ID của trang cần hiển thị rồi sau đó truy vấn nội dung của tin co ID này. Ví dụ: http://www.myhost.com/shownews.asp?ID=123. Mã nguồn của các trang này thường được viêt khá đơn giản theo dạng
<% Dim vNewID, objRS, strSQL
vNewID=Request("ID")
strSQL="Select * From T_NEWS Where NEW_ID=" & vNewID
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 lỗi. Tuy nhiên, giông như đoạn mã đăng nhập ở trên, đ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ế 1 ID hợp lệ bằng 1 ID khác và từ đó khởi đầu cho một cuộc tấn công. Ví dụ như: 0 OR 1=1 (nghĩa là http://www.myhost.com/shownews.asp?ID=0 or 1=1) Câu truy vấn SQL luc 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 T_NEWS Where NEW_ID=0 Or 1=1
Một trường hợp khác ví dụ như trang tìm kiếm. 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à:

<%
Dim vAuthorName, objRS, strSQL
vAuthorName=Request("fAUTHOR_NAME")
strSQL="Select * From T_AUTHORS Where AUTHOR_NAME=' " &_ vAuthorName & " ' "
Set objRS=Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
...
Set objRS=Nothing
%>

Tương tự như trên, kẻ tấn công có thể sữ dụng sơ hỡ trong câu truy vấn SQL để nhập vào trường tên tác giả một chuỗi: UNION Select All Select OtherField From OtherTable Where ' '=' (*) Lúc này câu truy vấn đầu tiên không thành công, chương trình sẽ thực hiện thêm câu lệnh sau từ khóa UNION
Tất nhiên tất cả các ví dụ nói trên không có gì là nguy hiểm nhưng nếu kẻ tấn công có thể xóa toàn bộ cơ sở dữ liệu bằng cách chèn các đoạn lênh nguy hiễm DROP TABLE như: ' DROP TABLE T_AUTHORS --
Bạn sẽ thắc mắc làm sao có thể biết được ứng dụng web bị lỗi dạng này? Rất đơn giản, hãy nhập chuỗi (*) như trên, nêu hệ thống báo về lỗi cú pháp: Invalid object name "OtherTable" ta có thể biết chắc là hệ thống đã thực hiện câu lệnh Select sau UNION vì như vậy hệ thống mới trả về lỗi mà ta cố tình tạo ra trong câu lềnh Select.
Cũng có thể bạn sẽ thắc mắc làm sao biết được tên của các bảng dữ liệu để mà thực hiện các thao tác phá hoại khi ứng dụng wed bị lỗi SQL injection? Cũng rất đơn giản vì trong SQL Server có 2 đối tượng sysobjects và syscolums cho phép liệt kê tất cả các tên bảng và tên cột có trong hệ thống. Ví dụ như : UNION Select name From sysobject Where xtype= ' U ' là có thể liệt kê được tên tất cả các bảng dữ liêu.