Trong bài viết này, chúng tôi sẽ đi sâu vào vấn đề SQL Injection với các trang web ASP.NET. Tuy nhiên, bạn cũng cần nhớ rằng SQL Inject có thể xảy ra ngay cả khi bạn sử dụng PHP với cơ sở dữ liệu MySQL, thậm chí Oracle cũng có thể mắc lỗi SQL Injection.
1. Đừng nghĩ rằng việc xác thực từ phía 'client-side' là đủ an toàn
Bắt đầu bằng cách giảm thiểu mã code phía server cho cáctrang Web ASP.NET. Không nên tin tưởng vào việc xác thực từ phía client-side vì điều này có thể dễ dàng bị phá vỡ. Chỉ sử dụng xác thực từ phía client-side để cải thiện trải nghiệm người dùng.
Để thực hiện điều này, bạn có thể loại bỏ các ký tự lạ hoặc thay thế chúng bằng các ký tự hợp lệ trong truy vấn SQL. Các ký tự đặc biệt trong SQL như dấu nháy đơn, dấu nháy kép, NULL, % --, ... (',',%,\r,\n,\t) .
- Đặc biệt cần chú ý với các biểu thức luôn luôn đúng: ' OR 1=1 OR ' . Nếu không chú ý, bạn có thể để cho kẻ tấn công hiển thị toàn bộ dữ liệu của bạn
ví dụ, câu SQL của bạn lấy thông tin của một người dùng cụ thể: select * from Users where uid='abc' , câu này chỉ trả về một bản ghi của người dùng đó nhưng kẻ tấn công có thể thêm vào select * from Users where uid='abc' OR 1=1 , dẫn đến việc trả về toàn bộ các bản ghi.
- Những ký tự chú thích ' --', '\xbf'
Giả sử nếu trước đó, giá trị SSN được nhập từ control TextBox của ASP.NET, bạn có thể hạn chế đầu vào bằng cách sử dụng control RegularExpressionValidator như sau:
Nếu đầu vào SSN được nhận từ một nguồn khác, ví dụ như control HTML, một tham số chuỗi truy vấn hoặc một cookie, bạn có thể hạn chế đầu vào bằng cách sử dụng lớp Regex từ namespace System.Text.RegularExpressions. Giả sử đầu vào được nhận từ một cookie.
Sử dụng System.Text.RegularExpressions:
Nếu (Regex.IsMatch(Request.Cookies['SSN'], '^\d{3}-\d{2}-\d{4}$'))
{
// truy cập cơ sở dữ liệu
}
else
{
// xử lý đầu vào không hợp lệ
}
2. Kiểm tra đầu vào của mã ở tầng truy cập dữ liệu.
Trong một số trường hợp tương tự, ngoài việc xác thực ở cấp độ trang ASP.NET, bạn cũng cần cung cấp xác nhận hợp lệ trong mã truy cập dữ liệu của mình. Hai trường hợp phổ biến mà bạn cần cung cấp xác nhận hợp lệ trong mã truy cập dữ liệu của mình:
- Client không đáng tin cậy: Nếu dữ liệu lấy từ một nguồn không đáng tin cậy hoặc bạn không thể đảm bảo rằng dữ liệu đã được xác thực và hạn chế, hãy thêm logic xác thực để hạn chế đầu vào trong mã truy cập dữ liệu.
- Mã thư viện (mã nguồn thư viện): Nếu mã truy cập dữ liệu của bạn được đóng gói dưới dạng một thư viện được thiết kế để sử dụng cho nhiều ứng dụng, mã truy cập dữ liệu đó phải thực hiện xác nhận hợp lệ của chính nó, bởi vì bạn không thể giả định rằng ứng dụng client là an toàn.
Dưới đây là một ví dụ về cách các đối tượng truy cập dữ liệu xác nhận hợp lệ cho các tham số đầu vào bằng cách sử dụng các biểu thức thông thường trước khi sử dụng chúng trong các lệnh SQL.
sử dụng System;
sử dụng System.Text.RegularExpressions;
public void TạoTàiKhoảnMới(string tên, string mật khẩu)
{
// Kiểm tra tên chỉ chứa chữ thường hoặc chữ hoa, dấu ' (apostrophe), dấu chấm hoặc khoảng trắng. Kiểm tra cũng phải từ 1 đến 40 ký tự
if ( !Regex.IsMatch(userIDTxt.Text, @'^[a-zA-Z'./s]{1,40}$'))
throw new FormatException('Định dạng tên không hợp lệ');
if ( !Regex.IsMatch(passwordTxt.Text,
@'^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$' ))
throw new FormatException('Định dạng mật khẩu không hợp lệ');
}
Đoạn mã sau đây mô tả cách sử dụng SqlParameterCollection khi gọi Stored Procedure:
sử dụng System.Data;
sử dụng System.Data.SqlClient;
sử dụng (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet dữLiệuNgườiDùng = new DataSet();
SqlDataAdapter lệnhCủaTôi = new SqlDataAdapter(
'ThủTụcĐăngNhập', connection);
lệnhCủaTôi.SelectCommand.CommandType = CommandType.StoredProcedure;
lệnhCủaTôi.SelectCommand.Parameters.Add('@au_id', SqlDbType.VarChar, 11);
lệnhCủaTôi.SelectCommand.Parameters['@au_id'].Value = SSN.Text;
lệnhCủaTôi.Fill(dữLiệuNgườiDùng);
}
Trong trường hợp này, tham số @au_id được coi như một giá trị chữ, không phải là mã thực thi. Ngoài ra, tham số này được kiểm tra về loại và độ dài. Trong đoạn mã trước, giá trị đầu vào không được dài hơn 11 ký tự. Nếu dữ liệu không phù hợp với loại hoặc độ dài được xác định bởi tham số, lớp SqlParameter sẽ bỏ ngoại lệ.
Sử dụng tham số Batch
Một quan niệm sai lầm là nếu bạn nối một vài câu lệnh SQL để gửi hàng loạt các câu lệnh đến máy chủ trong một quy trình, bạn không thể sử dụng tham số.
Tuy nhiên, bạn có thể áp dụng phương pháp này nếu chắc chắn rằng tên tham số không bị trùng lặp. Bạn có thể dễ dàng thực hiện điều này bằng cách đảm bảo chỉ sử dụng các tên tham số duy nhất trong SQL, như ví dụ dưới đây:
sử dụng System.Data;
sử dụng System.Data.SqlClient;
. . .
using (SqlConnection kếtNối = new SqlConnection(connectionString))
{
SqlDataAdapter bộTruyVấn = new SqlDataAdapter(
'SELECT MãKháchHàng INTO #Tạm1 FROM KháchHàng ' +
'WHERE MãKháchHàng > @mãKháchHàng; SELECT TênCôngTy FROM KháchHàng ' +
'WHERE QuốcGia = @quốcGia và MãKháchHàng TRONG ' +
'(SELECT MãKháchHàng FROM #Tạm1);',
kếtNối);
SqlParameter thamSốMãKháchHàng = bộTruyVấn.SelectCommand.Parameters.Add(
'@mãKháchHàng', SqlDbType.NChar, 5);
thamSốMãKháchHàng.Value = mãKháchHàng.Text;
SqlParameter thamSốQuốcGia = bộTruyVấn.SelectCommand.Parameters.Add(
'@quốcGia', SqlDbType.NVarChar, 15);
thamSốQuốcGia.Value = quốcGia.Text;
kếtNối.Open();
DataSet bộDữLiệu = new DataSet();
bộTruyVấn.Fill(bộDữLiệu);
}
Phần hướng dẫn trên Mytour vừa chỉ cho bạn cách ngăn chặn tấn công SQL Injection vào ASP.NET. Điều quan trọng nhất là bạn nên xác nhận tất cả đầu vào của ứng dụng ASP.NET để ngăn chặn tấn công SQL Injection vào ASP.NET.
Thêm một số nguyên tắc về bảo mật SQL:
- Vô hiệu hóa người dùng sa: Người dùng sa mặc định thường có quyền hạn cao đến mức làm cho tin tặc có thể can thiệp vào hệ thống, vì vậy hãy vô hiệu hóa chúng.
- Sử dụng người dùng với quyền hạn cần thiết và phù hợp: Thay vì một người dùng có quyền truy cập vào tất cả các cơ sở dữ liệu, hãy sử dụng một người dùng cho mỗi cơ sở dữ liệu, với quyền hạn chỉ cho phép truy cập đến cơ sở dữ liệu đó, thậm chí bạn cần tạo ra các người dùng mới chỉ có thể truy cập đến mức tối thiểu của bảng, thủ tục lưu trữ, và chế độ xem...
- Mã hóa chuỗi kết nối tới cơ sở dữ liệu, điều này rất hữu ích khi bạn vô tình tiết lộ tệp .config.
- Cài đặt tường lửa trên cổng dành cho SQL: Thông thường, cổng cho Microsoft SQL là 1433, và cho MySQL là 3306.
Hiện nay, có thông tin về Microsoft giới thiệu công cụ Phát hiện Rủi ro Bảo mật dựa trên trí tuệ nhân tạo để phát hiện sớm các lỗ hổng bảo mật trên máy tính, nhằm bảo vệ dữ liệu tốt hơn. Chúng ta sẽ chờ đợi và trải nghiệm công cụ Phát hiện Rủi ro Bảo mật từ Microsoft trong thời gian sớm nhất.
Trong thời gian chờ đợi sự che chở từ Microsoft, bạn có thể tìm hiểu về Oracle - một cơ sở dữ liệu khá nổi tiếng và được ưa chuộng trong các hệ thống đòi hỏi sự tin cậy cao như viễn thông, ngân hàng, khối chính phủ... So sánh SQL Server và Oracle
