Lựa chọn hàng đầu để ngăn chặn SQL Injection

Lựa chọn hàng đầu để ngăn chặn SQL Injection

SQL là gì?

SQL là viết tắt của Structured Query Language (Ngôn ngữ truy vấn có cấu trúc). SQL được sử dụng để giao tiếp trực tiếp với cơ sở dữ liệu. Nó được phát âm là ess-que-el hoặc see-que-el. Để quản lý cơ sở dữ liệu, nó là ngôn ngữ tiêu chuẩn được thiết lập bởi Viện Tiêu chuẩn Quốc gia Hoa Kỳ (ANSI). Vậy SQL để làm gì? Giống như trang web của phụ thuộc vào HTML, CSS, JavaScript để hoạt động, còn SQL được sử dụng để sửa đổi, cập nhật, thực hiện các thay đổi đối với cơ sở dữ liệu.

SQL Server, Microsoft Access, Informix, Oracle, Sybase là một vài hệ quản trị cơ sở dữ liệu hoạt động với SQL. Chỉ huy một cơ sở dữ liệu không cần phải viết kịch bản phức tạp. Hầu hết các tập lệnh đều được mã hóa trước và được đẩy như các quy tắc với hệ thống quản lý cơ sở dữ liệu (DBMS). Chúng tôi sử dụng các lệnh đơn giản như UPDATE, SELECT, INSERT, DELETE, FROM, LIKE, WHERE, v.v. theo sau là dấu hỏi ? giúp tương tác thường xuyên với cơ sở dữ liệu.

Thế nào là SQL Injection

Những kẻ săn mồi tấn công với cùng một kiến thức hoặc đánh lừa các công cụ để đạt được mục đích có thể gọi là một cuộc tấn công SQL. Những kẻ xấu chèn tập lệnh SQL độc hại vào cơ sở dữ liệu khi đó chúng có tên gọi là SQL injection.

Các cuộc tấn công của những kẻ săn mồi khá phổ biến và chúng được thực hiện trong thời gian dài. Chúng có thể lấy thông tin người dùng, thậm chí cả thông tin đăng nhập quản trị viên chỉ thông qua cuộc tấn công SQL và kiểm soát toàn bộ trang web. Những kẻ săn mồi có khả năng thực hiện bất kỳ mục đích nào mà dữ liệu được truy cập. Nếu cơ sở dữ liệu của bạn không an toàn, đầu vào không được xác thực đầy đủ, ... thì máy chủ rất dễ dàng có thể bị chèn SQL. Có rất nhiều điểm yếu khác nhau mà một ứng dụng web có thể mắc phải, vậy làm cách nào mà những kẻ săn mồi có thể tìm được những con mồi ngon cho mình và cách nào để chúng ta là những con mồi ấy được an toàn tính mạng? Trong bài viết này, mình sẽ chỉ ra những lựa chọn sinh tồn hàng đầu trong môi trường web.


SELECT ? FROM ? WHERE ? LIKE? '%keyword%';

Dòng lệnh đơn giản này trên cơ sở dữ liệu được sử dụng để tìm một mục cụ thể. Góc nhìn chung của người dùng có thể là thanh tìm kiếm nơi keyword đang được sử dụng. Nó trông giống hệt như hình ảnh, tùy thuộc vào IDE được sử dụng từ bộ tiêm hoặc khách hàng tiềm năng của trình quản lý cơ sở dữ liệu.


SELECT ? FROM ? WHERE ? LIKE? '%';-- %;

Ở đây, mình đã sửa đổi mã một chút để kiểm tra xem máy chủ có phản hồi gì với truy vấn. Mình đã thay đổi từ khóa bên trong các dấu ngoặc kép để xem máy chủ hoặc mục tiêu phản hồi như thế nào.

Ta có thể phân biệt nhiều cách khác nhau để biết đang sử dụng cơ sở dữ liệu nào, ở trên đây mình đang sử dụng MySQL.


SELECT ? FROM ? WHERE ? LIKE? '%keyword'; AND 1 = SLEEP(10); -- %';

Việc ủ với chức năng trì hoãn có thể nhanh chóng tiết lộ DBMS nào đã được sử dụng. Ở trên, sau từ khóa, chúng ta đặt một hàm trì hoãn. Trên MySQL, hàm trì hoãn là SLEEP Vì vậy, chúng tôi đặt chức năng trì hoãn trong một vài giây. Sau khoảng thời gian 10 giây mà chúng tôi chỉ định, máy chủ sẽ gửi thông tin. Và đây là cách chúng ta có thể xác định loại máy chủ SQL được sử dụng. MySQL sử dụng hàm "SLEEP" và Oracle sử dụng DBMS_SESSION.SLEEP hoặc DBMS_LOCK.SLEEP. Vâng, việc tìm ra các khía cạnh nhất định một cách dễ dàng chỉ bằng hành vi quản lý thời gian hoặc trì hoãn là điều khá bình thường.

Làm sao để ngăn chặn tấn công SQL Injection

Có nhiều cách để ôn luyện với cơ sở dữ liệu SQL; có nhiều cách hơn để đảm bảo rằng chúng không bị chú ý. Chúng tôi sẽ chỉ ra các cách UpToDate nhất để ngăn chặn việc tiêm SQL.

Chuẩn bị gì?

Các nhà phát triển có kinh nghiệm không bỏ chọn phần này, vì việc chuẩn bị các câu lệnh là một trong những quy tắc chính và quan trọng nhất để ngăn chặn việc tiêm SQL. Các truy vấn được tham số hóa đôi khi được gọi là các câu lệnh chuẩn bị. Các câu lệnh chuẩn bị hoạt động với một ràng buộc biến. Liên kết biến và truy vấn động hoạt động song song với nhau. Nhưng chúng đơn giản hơn để viết và cuối cùng thực hiện trong cơ sở dữ liệu. Điều mà một câu lệnh chuẩn bị thực hiện đối với cơ sở dữ liệu là nó xác định truy vấn SQL trước khi truyền các tham số. Kết quả là, truy vấn trở nên tinh tế và không thể thay đổi bởi những kẻ tấn công.


Java = PreparedStatement()
DotNET = sqlCommand() and OleDbCommand()
PHP = (using bindParam())
SQLite = sqlite3_prepare()

Dưới đây là một số kiểu câu lệnh Prepared khác nhau của các ngôn ngữ lập trình khác nhau. Việc tham số hóa các truy vấn khiến kẻ tấn công khó chèn một truy vấn. Trước đây chúng tôi đã nêu các lệnh được sử dụng trong SQL injection. Mỗi ngôn ngữ có cách sử dụng mỏ tham số hóa.


<?php
	include_once 'dbh.inc.php';
    
    $first = mysqli_real_escape_string($conn, $_POST['first']);
    $last = mysqli_real_escape_string($conn, $_POST['last']);
    $uid = mysqli_real_escape_string($conn, $_POST['uid']);
    $email = mysqli_real_escape_string($conn, $_POST['email']);
    $pwd = mysqli_real_escape_string($conn, $_POST['pwd']);
    
    $sql = "INSERT INTO users (user_first, user_last, user_uid, user_email, user_pwd) VALUES ('$first', '$last', '$uid', '$email', '$pwd'); ";
    mysqli_query($conn, $sql);
    
    header("Location: ../index.php?signup=success");

Như chúng ta có thể thấy, các biến PHP đã được thiết lập giống như mọi hàm khác trong mã. Mọi việc gán các biến như tên người dùng, id người dùng, mật khẩu, chức năng email đã được khai báo trong tập lệnh của chúng tôi. Những gì chúng ta cần làm bây giờ là, điều khiển các biến cụ thể để hoạt động trên các vai trò đã cho.


$stmt->bind_param("sss", $firstname, $lastname, $email);

So với việc thực thi SQL, các câu lệnh chuẩn bị nói chuyện trực tiếp với cơ sở dữ liệu để có những lợi thế như giảm thời gian phân tích cú pháp và loại bỏ lỗ hổng SQL injection. Nó nhận các tham số đơn lẻ trong khi làm việc với nó thay vì toàn bộ truy vấn.


$stmt = $dbh->prepare("SELECT * FROM users WHERE USERNAME = ? AND PASSWORD = ?");
$stmt->execute(array($uid, $pwd));

Đây là một câu lệnh khác nằm trong câu lệnh đã chuẩn bị và các truy vấn được tham số hóa. Đó là một cách an toàn để tiến hành mã hóa cơ sở dữ liệu SQL. Các câu lệnh được tham số hóa là một trong những phần quan trọng của việc bảo vệ chống lại việc tiêm SQL.

Xác thực đầu vào

Xác thực đầu vào là một trong những biện pháp bảo vệ chính hoạt động với các phương pháp ngăn chặn việc đưa vào SQL ở tuyến đầu. Nói một cách dễ hiểu, bất kể đầu vào nào ở đó, quá trình xác nhận sẽ phân tích xem loại đầu vào có được phép hay không. Và thậm chí loại người dùng nào cũng có quyền sử dụng loại đầu vào này. Đầu vào là số nguyên (số nguyên, cả số dương và số âm), văn bản thuần túy (từ đơn giản), số trôi nổi (số có dấu thập phân). Bên ngoài tham số đó hoặc một hàm có cấu trúc cụ thể sẽ bị bỏ qua và hoạt động như xác thực đầu vào.

Xác thực đầu vào OWASP hoặc OWASP WebGoat là một nền tảng đơn giản hóa dạy thực hành chung về xác thực đầu vào. Có một số lượng đáng kể các trường đầu vào khác với chúng tôi đã đề cập ở trên. Trình tải tệp hoặc tài liệu lên, các trang web hiện đại hoạt động với AI có nhiều loại trường đầu vào khác nhau. Đây là các giá trị được xác định trước bằng các nút hoặc đầu vào với các tùy chọn trắc nghiệm. Xác thực đầu vào chỉ chấp nhận đầu vào được xác định trước do đó loại bỏ việc lạm dụng cơ sở dữ liệu. Một quy tắc chung để xác thực đầu vào là đưa vào danh sách trắng các biểu thức chính quy thay vì đưa vào danh sách đen. Việc xác thực bao gồm thông tin người dùng chung như tên, tuổi hoặc mã zip, v.v. Nên có một tập hợp các trường hợp cố định.


<?php
if(isset($_POST["selectMode"])) {
	$number = $_POST["selectMode"];
    if(is_numeric($number)) && ($number > 0) && ($number < 6)) {
    	echo "SelectMode: " . $number;
    } else
    	echo "Chế độ đã được thay đổi từ Sáng sang Tối";
}

Trong đoạn mã PHP này, chúng tôi đã đề cập đến một ví dụ phổ biến về mã thực tế. "Chế độ" ở đây xác định chủ đề cơ bản của một giao diện. Đầu vào lấy dữ liệu người dùng và biến đổi trang web cho phù hợp. Ở đây, các chế độ là "Sáng" và "Tối". Nó phổ biến trong hầu hết các ứng dụng web ngày nay. Đầu vào này nên được xác định trước về việc thay đổi cài đặt nào và tác động của nó đến cơ sở dữ liệu như thế nào. Thay vào đó, nó không nên có quyền thay đổi bất kỳ chức năng nào khác. Đây là đầu vào nút radio. Tương tự đối với các đầu vào không gian trống. Mục tiêu của chúng tôi là xác định các chức năng càng chính xác càng tốt.

Escaping

Bất cứ khi nào chúng tôi yêu cầu dữ liệu từ cơ sở dữ liệu, nó sẽ tìm cách dễ nhất và "nhanh nhất" để phân tích truy vấn. Điều phức tạp là cách chúng tôi xác định truy vấn, những gì chúng tôi muốn truy cập và cách máy chủ SQL xử lý việc thực thi. Một trong những cách quan trọng mà kẻ tấn công có thể thực hiện một SQL injection là sử dụng lỗi phổ biến này. Bỏ qua tất cả các hàm ký tự có thể làm cho hệ thống hơi lộn xộn, nhưng này, chúng tôi đã không chọn quản lý SQL cho giải pháp nhanh nhất hiện có. Thay vào đó, chúng tôi quyết định chọn SQL vì thân thiện với người dùng, an toàn và chính xác với dữ liệu của chúng tôi. Một phương pháp thoát đơn giản là thêm một dấu ngoặc kép theo sau là một ký tự thoát ('\).


$_POST['password']);
	$query = "SELECT * FROM users WHERE username = '" . $username . "' AMD password = '" . $password . "'";

Đối với Hệ thống quản lý cơ sở dữ liệu (DBMS), chúng tôi khuyên bạn nên thoát các ký tự do người dùng xác định. Điều khác biệt giữa phần thoát và phần không thoát là, nó không gây nhầm lẫn giữa dữ liệu bên ngoài với lệnh quản trị. Nếu các câu lệnh đã chuẩn bị hoạt động chính xác, việc thoát khỏi mọi ký tự là không cần thiết. Đó là một lưu ý quan trọng không thể đề cập đến. Bởi vì các ký tự được tham số hóa đã chứa một số ký tự thoát.

Tường lửa & Quyền quản trị

Một phương pháp tiêu chuẩn để lấy thông tin nhạy cảm thông qua SQL injection là chiếm chính tài khoản quản trị viên. Tài khoản quản trị viên giữ tất cả các quyền xóa, sửa đổi và chèn dữ liệu. Ngoài ra, nó có thể thêm một người ngoài có đủ đặc quyền để làm nhiều việc như tài khoản quản trị vì nó có quyền truy cập root. Khuyến nghị của chúng tôi là không sử dụng tài khoản quản trị trong cơ sở dữ liệu. Các tài khoản khác có đặc quyền công bằng vì tài khoản quản trị viên có các mối đe dọa tương tự. Mỗi ứng dụng phải có cơ sở dữ liệu của nó để đảm bảo an toàn cho toàn bộ ứng dụng web. Khi tạo tài khoản với nhiều tính năng nhỏ hơn, đừng lấy đi các dấu tích đặc quyền; thay vào đó, hãy đánh dấu chỉ quan trọng cho nhiệm vụ. Bằng cách này, sẽ dễ dàng theo dõi và duy trì một hệ thống ổn định và an toàn.

Tường lửa cũng rất quan trọng để bảo vệ khỏi việc tiêm SQL vì chúng bảo vệ cơ sở dữ liệu và hệ thống ngay cả khi không có sự tiếp xúc của con người — các quy tắc và thủ tục xác định trước được đặt bởi phương pháp chèn SQL tiêu chuẩn giúp tường lửa luôn được cập nhật. Tường lửa Ứng dụng Web (WAF) giám sát lưu lượng truy cập và quan trọng nhất là đặt một hàng rào hoạt động như một lá chắn chống lại các mối đe dọa cấp thấp. Có thể dễ dàng thêm các chính sách và quy tắc vượt tường lửa mà không cần báo động giả. Một giải pháp tường lửa tuyệt vời là PTSecurity. Họ cũng tung ra các bản cập nhật thường xuyên về những gì mới trong bộ phận tường lửa. Tường lửa thường chặn việc đưa vào SQL, chụp cookie, giả mạo tham số và đưa ra phân tích dữ liệu lưu lượng truy cập theo thời gian thực.

Union & Mã hóa mật khẩu

Các khóa liên minh là khá quan trọng khi nói đến các phương pháp ngăn chặn tiêm SQL. Tổng hợp hai hoặc nhiều truy vấn trong một kết quả duy nhất là công việc của khóa liên minh. Các truy vấn này thuộc hàng liên hợp. Giả sử A U B là một hàm. A có tập {1,2,3} & B gồm {4,5}. Nếu chúng ta sử dụng công thức liên hợp chung, thì nó sẽ trở thành {1,2,3,4,5}. Nguyên tắc chung này có thể kết hợp với nhiều hàng hơn để đưa ra kết quả mong muốn, như ở hàng 5, cột 8. Đúng vậy, với loại chính xác này, liên minh hoạt động. Chúng tôi có thể triển khai nhiều truy vấn trong một liên hợp.


SELECT column_name(s) FROM table1
UNION ALL
SELECT column_name(s) FROM table2;

Mặt khác, để truy cập cơ sở dữ liệu, chúng ta cần mật khẩu. Mật khẩu càng an toàn, kẻ tấn công càng khó bẻ khóa. Mật khẩu đơn giản có thể được bẻ khóa một cách ngắn gọn bằng cách ép buộc, lừa đảo, ghi khóa và nhiều cách khác. Mặc dù chúng cần được thay đổi định kỳ, nhưng hầu hết định nghĩa của nó phụ thuộc vào sức mạnh. Mật khẩu băm giống như mã hóa.


mysql_native_password

caching_sh2_password

sha256_password

Nhiều cách khác nhau mà chúng ta có thể băm mật khẩu, sh256, bộ nhớ đệm là một số cách tốt hơn. Đây là một số cách chính để bảo vệ khỏi việc tiêm SQL.

Tác giả: Jos Hoàng Tiên
Hãy mua cho mình một cuốn notebook và một cây bút kể cả khi bạn là dân coder.