HomeBlogTấn công SQL injection là gì? Nguy hiểm đến mức nào và làm sao để phòng tránh?
Operations Security

Tấn công SQL injection là gì? Nguy hiểm đến mức nào và làm sao để phòng tránh?

CyStack blog11 phút để đọc
CyStack blog14/09/2023
Locker Avatar

Trung Nguyen

CEO @CyStack

Locker logo social

CEO @CyStack

Reading Time: 11 minutes

Trong tất cả các cuộc tấn công nhằm vào website, tấn công SQL Injection là một loại hình nguy hiểm và phổ biến nhất, nó đã gây ra những thiệt hại đáng kể cho nhiều doanh nghiệp và tổ chức trong những năm qua.

SQL injection – còn được gọi là SQLi – sử dụng những lỗ hổng trong các kênh đầu vào (input) của website để nhắm mục tiêu vào cơ sở dữ liệu nằm trong phần phụ trợ của ứng dụng web, nơi lưu giữ những thông tin nhạy cảm và có giá trị nhất. Chúng có thể được kẻ tấn công sử dụng để ăn cắp hoặc xáo trộn dữ liệu, cản trở sự hoạt động của các ứng dụng, và, trong trường hợp xấu nhất, nó có thể chiếm được quyền truy cập quản trị vào máy chủ cơ sở dữ liệu. Dưới đây là những gì bạn cần biết về tấn công SQL Injection và cách bảo vệ website của bạn khỏi chúng.

Cách thức website bị tấn công SQL Injection

Các cuộc tấn công SQL Injection được thực hiện bằng cách gửi lệnh SQL độc hại đến các máy chủ cơ sở dữ liệu thông qua các yêu cầu của người dùng mà website cho phép. Bất kỳ kênh input nào cũng có thể được sử dụng để gửi các lệnh độc hại, bao gồm các thẻ<input>, chuỗi truy vấn (query strings), cookie và tệp tin.

Để xem cách nó hoạt động, giả sử bạn có một form đăng nhập có 2 input username và password như dưới đây:

Form đăng nhập gồm 2 input username và password.
Form đăng nhập gồm 2 input username và password.

Khi người dùng nhập thông tin đăng nhập của họ và nhấn vào nút “log in”, thông tin sẽ được gửi lại cho máy chủ web của bạn, ở đó nó sẽ được kết hợp với một lệnh SQL. Ví dụ, trong PHP, mã sẽ giống như sau:

$sql_command="select * from users where username = '".$_POST['username'];
$sql_command.="' AND password = '".$_POST['password']."'";

Lệnh này sau đó sẽ được gửi đến một máy chủ cơ sở dữ liệu và tập dữ liệu kết quả sẽ xác định xem username và password có tương ứng với một tài khoản người dùng hợp lệ hay không. Ví dụ người dùng nhập “john” làm username và “123456” làm password (đừng bao giờ sử dụng mật khẩu này) sẽ chuyển mã trên thành lệnh sau:

SELECT * FROM users WHERE username='john' AND password='123456'

Nhưng điều gì sẽ xảy ra nếu người dùng quyết định thử cái khác, chẳng hạn như sau:

Người dùng cố tình thay đổi username và password
Người dùng cố tình thay đổi username và password

Lệnh kết quả sẽ là như sau:

SELECT * FROM users WHERE username='john' OR 1=1; -- ' AND password='123456'

Kết quả trả về là thông tin đăng nhập của người dùng có tên là “john” mà không cần mật khẩu chính xác.
Đây chỉ là một trong những hình thức đơn giản nhất của tấn công SQL Injection. Với một vài thủ thuật, kẻ tấn công có thể thêm tài khoản mới, và xóa hoặc sửa đổi thông tin của các tài khoản người dùng hiện có. Cùng một cách tấn công có thể được sử dụng để lấy cắp các bản hồ sơ và thông tin của người dùng nếu chúng không bị giới hạn cho khách truy cập hoặc để thay đổi nội dung hồ sơ.
Trong các trường hợp nghiêm trọng hơn, khi kết nối với máy chủ cơ sở dữ liệu được thực hiện thông qua tài khoản quản trị (như “root” trong MySQL hoặc “sa” trong MS SQL Server), kẻ tấn công có thể đi sâu vào hệ điều hành của máy chủ. Kẻ tấn công sử dụng lỗ hổng SQL injection để cùng lúc tạo tài khoản người dùng trên máy chủ bị xâm nhập, kích hoạt tính năng Remote Desktop, cài đặt thư mục chia sẻ SMB và tải phần mềm độc hại – ngoài việc làm rối tung mọi thứ đã được lưu trữ trong cơ sở dữ liệu.

Làm sao để tự vệ với các cuộc tấn công SQL Injection?

Với vectơ chính cho các cuộc tấn công SQL Injection là các kênh input của người dùng, hầu hết các phương pháp phòng đều thủ liên quan đến kiểm soát input của người dùng
Dưới đây là một số biện pháp có thể đảm bảo an toàn cho input của người dùng.

Đừng bao giờ tin tưởng vào input của người dùng

Quy tắc đầu tiên về input mà người dùng nhập là “don’t trust and verify” (không tin tưởng và cần xác minh”), có nghĩa là tất cả những gì người dùng nhập vào phải được coi là độc hại trừ khi có bằng chứng khác. Nó không chỉ dành cho các hộp nhập liệu đơn giản như các vùng văn bản mà còn cho mọi thứ khác – như input ẩn, các chuỗi tham số truy vấn, cookie và tệp tải lên.
Browsers của trình duyệt không cho phép người dùng thao tác với một input, không nghĩa là nó không thể bị giả mạo. Các công cụ đơn giản như Burp Suite cho phép người dùng chiếm được HTTP requests và sửa đổi bất cứ điều gì, kể cả các giá trị dạng ẩn, trước khi gửi chúng tới máy chủ. Và nếu bạn nghĩ mình là người thông minh bằng cách sử dụng Base 64 mã hóa dữ liệu, bạn đã nhầm, nó có thể dễ dàng được giải mã, sửa đổi và mã hoá lại bởi kẻ tấn công

Xác nhận các chuỗi input ở phía máy chủ

Xác nhận là quá trình đảm bảo dữ liệu người dùng nhập vào là hợp lệ và vô hiệu hóa bất kỳ lệnh độc hại tiềm ẩn nào có thể được nhúng trong chuỗi nhập. Ví dụ, trong PHP, bạn có thể sử dụng mysql \ _real \ _escape \ _string () để thoát các ký tự có thể thay đổi bản chất của lệnh SQL.
Mã đăng nhập được đề cập trước đó sẽ được thay đổi như sau:

$con=mysqli_connect("localhost","user","password","db");
$username = mysqli_real_escape_string($con, $_POST['username']);
$password = mysqli_real_escape_string($con, $_POST['password']);
$sql_command = "select * from users where username = '" . $username; $sql_command .= "' AND password = '" . $password . "'";

Sửa đổi đơn giản này sẽ bảo vệ mã của bạn khỏi cuộc tấn công SQL Injection bằng cách thêm một ký tự thoát (\) phía trước dấu nháy đơn đã được kẻ tấn công thêm vào.
Ghi chú về xác nhận: Sẽ rất tốt nếu bạn đã thêm các chức năng xác thực phía máy khách. Nhưng không nên dựa vào nó như là một biện pháp phòng thủ chống lại các cuộc tấn công SQL injection. Mặc dù các chức năng phía máy khách có thể làm nó khó có thể gửi dữ liệu input nguy hiểm vào máy chủ của bạn, nhưng chức năng này có thể dễ dàng bị phá vỡ bằng một số browser tweak và công cụ khác. Vì vậy, bạn cần phải bổ sung thêm việc xác nhận phía máy chủ.
Một số nền tảng lập trình, chẳng hạn như ASP.NET, bao gồm các tính năng tích hợp sẽ tự động đánh giá input của người dùng nhưng các tin tặc đủ thông minh và tinh tế vẫn có thể phá hoại chúng, vì vậy bạn nên có 1 quy trình chặt chẽ kiểm định input của khách hàng, điều đó sẽ chẳng bao giờ là quá thận trọng.

Sử dụng các câu lệnh tham số

Một lựa chọn tốt hơn để thoát khỏi tấn công SQL Injection là sử dụng các câu lệnh tham số. Các câu lệnh tham số được định nghĩa bằng cách thêm tên của placeholder vào các lệnh SQL, thứ sau này sẽ được thay thế bởi input của người dùng. ASP.NET có một bộ API rất trực quan và dễ sử dụng cho mục đích này.
Đoạn mã sau, được viết bằng C#, cho thấy cách bạn có thể sử dụng các câu lệnh tham số để bảo vệ trang web của bạn khỏi tấn công SQL Injection:

SqlCommand cmd = new SqlCommand ("SELECT * FROM users WHERE username=@username AND password=@password",con);
SqlParameter username = new SqlParameter(); username.ParameterName = "@username"; username.value = txtUsername.Text; cmd.Parameters.Add(username);
SqlParameter password = new SqlParameter(); password.ParameterName = "@password"; password.value = txtPassword.Text; cmd.Parameters.Add(password);

Bạn bắt đầu bằng cách tạo ra một SqlCommand object và sử dụng placeholder @parameter_name trong chuỗi lệnh nơi mà dữ liệu người dùng nhập vào nên được chèn vào.
Sau đó bạn tạo instance của các SqlParameter object, trong đó bạn chèn input của người dùng, thay vì chèn trực tiếp nó vào chuỗi lệnh.
Cuối cùng, bạn thêm SqlParameter object vào bộ tham số SqlCommand object, nó sẽ thay thế các tham số bằng input được cung cấp.
Trong PHP sẽ có PDO và mysqli có thể giải quyết giống như ASP.net. Bạn có thể tham khảo ở đây.

Phân định rõ ràng kiểu input

Mẹo này dành cho các ngôn ngữ như PHP, khi bạn thường không định nghĩa các kiểu dữ liệu cho các biến số
Việc định nghĩa rõ ràng kiểu input như một cách để loại bỏ những dữ liệu có thể gây sai cho câu lệnh SQL. Vì vậy, nếu bạn đang mong đợi người dùng nhập “int” cho tham số “age”, bạn có thể đảm bảo sự an toàn của input với mã sau đây trong PHP:

$age = (int)$_POST['age'];

Lưu ý rằng đoạn mã này chỉ xác nhận kiểu của input chứ không phải phạm vi của nó. Vì vậy, bạn sẽ phải chạy mã khác để đảm bảo người dùng không nhập vào dữ liệu không hợp lệ
Ngoài ra,hành động tốt nhất là tránh sử dụng các dấu nháy đơn trong các lệnh SQL khi không có string được truyền vào. Thay vì sử dụng mã sau đây …

$sql_command = "select * from users where age = " . $age;

… sẽ an toàn hơn nếu bạn sử dụng lệnh sau:

$sql_command = "select * from users where age = '" . $age . "'";

Làm thế nào để diệt tận gốc các lỗ hổng SQL Injection?

Làm thế nào để diệt tận gốc các lỗ hổng SQL injection.
Làm thế nào để diệt tận gốc các lỗ hổng SQL injection.

Bạn nên kiểm tra mã của mỗi trang, ở những nơi mà bạn kết hợp nội dung trang, các lệnh, các chuỗi, v.v … với dữ liệu đến từ người dùng. Rà soát lại mã nguồn, tìm kiếm lỗ hổng bảo mật phải là một phần thiết yếu trong quá trình phát triển phần mềm của bạn.
Bạn cũng có thể sử dụng các công cụ quét như sql map để thu thập thông tin về các lỗ hổng SQL injection tiềm ẩn. Trên thực tế, tin tặc cũng thường sử dụng công cụ này để tìm và khai thác các vectơ tấn công SQL Injection trên các website mục tiêu. Hay đơn giản hơn bạn có thể sử dụng CyStack Platform để quét và phát hiện các lỗ hổng bảo mật một cách miễn phí để bảo vệ cho website của mình.

Hàng rào phòng thủ cuối cùng của bạn

Cho dù bạn cài đặt bảo mật cho website cao tới mức nào đi nữa, bạn vẫn phải sẵn sàng phòng bị cho ngày bị tấn công SQL injections. Chúng ta phải chiến thắng mọi cuộc chiến, nhưng tin tặc chỉ cần giành chiến thắng một lần.
Dưới đây là một số mẹo sẽ giúp bạn giảm tối thiểu thiệt hại khi bạn trở thành nạn nhân của tấn công SQL Injection.

Tránh quyền quản trị

Sử dụng tài khoản “root” hoặc “sa” để kết nối ứng dụng web với máy chủ cơ sở dữ liệu là một trong những sai lầm tồi tệ nhất mà bạn có thể mắc phải. Như đã được đề cập, một tài khoản quản trị bị xâm nhập có thể cho phép hacker truy cập vào toàn bộ hệ thống. Ngay cả những tài khoản không phải tài khoản quản trị nhưng được trao quyền truy cập vào tất cả các cơ sở dữ liệu bên trong một máy chủ cũng có thể gây tổn hại, đặc biệt nếu máy chủ cơ sở dữ liệu đang được chia sẻ giữa các ứng dụng và cơ sở dữ liệu khác nhau.
Do đó, tốt nhất nên sử dụng tài khoản chỉ có quyền truy cập đọc- viết đơn giản để vào từng cơ sở dữ liệu riêng biệt, trong trường hợp website của bạn bị tấn công SQL Injection, phạm vi thiệt hại vẫn nằm trong ranh giới của cơ sở dữ liệu đó.
Trong MySQL, cải thiện bảo mật bằng cách hạn chế quyền truy cập vào tài khoản người dùng đến các dải địa chỉ IP cụ thể thay vì mô hình “%”, để ngăn các tài khoản bị xâm nhập bị truy cập từ xa.
Trong máy chủ MS SQL, bạn nên sử dụng mô hình Windows Authentication để hạn chế truy cập của hacker vào cơ sở dữ liệu và đảm bảo họ sẽ không thể sử dụng các kênh khác để truy cập vào cơ sở dữ liệu của bạn.
Ngoài ra, trừ khi bạn đang có kế hoạch sử dụng một số tính năng nâng cao của SQL Server, bạn nên thiết lập dịch vụ windows để sử dụng một tài khoản giới hạn thay vì “Local System”. Điều này sẽ giảm thiểu thiệt hại trong trường hợp tài khoản “sa” bị xâm nhập.

Mã hóa dữ liệu nhạy cảm

Mã hóa những dữ liệu nhạy cảm trong cơ sở dữ liệu của bạn. Nó bao gồm mật khẩu, câu hỏi và câu trả lời về bảo mật, dữ liệu tài chính, thông tin y tế và các thông tin khác có ích cho các tác nhân độc hại. Điều này sẽ đảm bảo rằng ngay cả khi tin tặc nắm trong tay dữ liệu của bạn, chúng sẽ không thể khai thác nó ngay lập tức, cho bạn thời gian để phát hiện ra sự vi phạm, đánh dấu và thực hiện các biện pháp phản ứng khác như thực thi khôi phục mật khẩu, đảm bảo rằng dữ liệu bị đánh cắp mất giá trị trước khi kẻ tấn công giải mã nó.

Mã hóa dữ liệu nhạy cảm làm hacker không thể khác thác ngay khi có được.
Mã hóa dữ liệu nhạy cảm làm hacker không thể khác thác ngay khi có được.

Nếu bạn đang hashing mật khẩu của mình, nên sử dụng các thuật toán mạnh như SHA-2, nó sẽ sớm trở thành tiêu chuẩn ngành công nghiệp để bảo vệ mật khẩu. MD5 và SHA-1 đã lỗi thời và có thể bị giải mã.
Đối với các hình thức mã hóa khác, hãy cẩn thận khi bạn cất giữ thông tin giải mã, và đừng bao giờ đặt chúng ở cùng 1 nơi. Sẽ thật vô nghĩa nếu bạn mã hóa dữ liệu nhưng lại đặt cách thức giải mã ngay cạnh chúng, hacker sẽ dễ dàng truy cập vào chúng ngay khi chúng xâm hại máy chủ

Không lưu trữ dữ liệu nhạy cảm không cần thiết

Khi bạn lưu trữ thông tin trong cơ sở dữ liệu, hãy xem nó sẽ gây tác hại như thế nào nếu bị rơi vào tay kẻ xấu, và quyết định xem bạn có thực sự cần lưu trữ nó hay không. Cuộc tấn công của Ashley Madison đã làm lộ những bí mật đen tối và thông tin mật của khoảng 37 triệu người trên internet và đã gây ra một số thiệt hại nghiêm trọng, một phần trong sự thành công của kẻ tấn công là do nhà cung cấp web đã không dọn dẹp các thông tin nhạy cảm từ cơ sở dữ liệu. Vì vậy, điểm mấu chốt là, không lưu trữ thông tin nhạy cảm trong cơ sở dữ liệu trừ khi bạn thực sự cần. Và thậm chí sau đó, xóa thông tin khi không còn sử dụng.

Kết luận

SQL Injection đã tồn tại quanh ta trong nhiều thập kỷ và có thể sẽ tiếp tục đứng đầu bảng xếp hạng các lỗ hổng nguy hiểm trong những năm tới. Chỉ mất một vài bước dễ dàng – nhưng sẽ là một sự toan tính rất tốt – để bảo vệ chính bạn và người dùng của bạn khỏi sự tấn công này, và lỗ hổng này sẽ là một trong những ưu tiên hàng đầu khi kiểm tra mã nguồn cho các lỗ hổng bảo mật.
Việc đầu tiên cần làm để tránh trở thành nạn nhân của cuộc tấn công tiếp theo về vi phạm dữ liệu SQL injection là kiểm soát và xác nhận input của người dùng, tiếp theo đó cần tự trang bị những công cụ cần thiết để bảo vệ cho website của mình một khi chúng ghé thăm.

CyStack blog

Mẹo, tin tức, hướng dẫn và các best practice độc quyền của CyStack

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.