Sql injection – Tấn công thay đổi hoặc làm lộ CSDL hệ thống

Trong các lỗi tấn công bảo mật căn bản, phổ biến nhất và cũng là một trong những lỗ hổng nguy hiểm nhất phải kể đến chính là lỗi: SQL injection. Một nghiên cứu gần đây cho thấy, gần một nửa số vụ tấn công bảo mật tới các hệ thống web có liên quan trực tiếp hoặc gián tiếp tới lỗ hổng SQL injection, điều đó đủ cho ta thấy tầm nghiêm trọng của lỗ hổng này. Vì vậy, việc trang bị kĩ năng phòng tránh lỗ hổng này gần như là bắt buộc đối với mọi lập trình viên cũng như mọi hệ thống phần mềm mà họ xây dựng.

Đây không phải là một lỗi bảo mật mới, ngược lại, nó đã xuất hiện từ rất lâu, nhưng không phải ai cũng biết (hoặc để ý) cách phòng tránh nó. Tấn công SQL injection có thể được coi là một phương pháp tấn công kinh điển trong thế giới bảo mật. Rất nhiều framework hiện đại sau này đã cung cấp các giải pháp phòng chống mặc định cho lỗi tấn công này, tuy nhiên điều này cũng dẫn tới 2 vấn đề chính:

  • Lập trình viên không hiểu được bản chất của lỗi tấn công SQL injection
  • Bởi vì đa phần các framework hiện đại đã hỗ trợ cách phòng tránh, dẫn tới việc lập trình viên lơ là cảnh giác. Nhưng vấn đề là: “đa phần” không có nghĩa là “tất cả”.

Chúng ta sẽ định nghĩa và phân tích tổng quan về nguyên nhân, tác hại cũng như cách phòng tránh, để giúp cho quá trình xây dựng hệ thống của chúng ta được an toàn hơn.

Tấn công SQL injection là gì

SQL injection là kĩ thuật cho phép các kẻ tấn công chèn và thực thi các lệnh SQL bất hợp pháp (mà người phát triển không lường trước được) bên trong hệ thống, bằng cách lợi dụng các lỗ hổng bảo mật từ dữ liệu nhập vào của các ứng dụng. Qua đó làm lộ thông tin trong cơ sở dữ liệu, tạo ra sự sai lệch hoặc gây hư hỏng dữ liệu của hệ thống.

Một cách nôm na, ta có thể hiểu tấn công SQL injection là việc truyền vào các mã SQL thông qua các ô nhập liệu, để làm thay đổi mục đích câu truy vấn ban đầu. Với định nghĩa trên, ta có thể tạm chia SQL injection thành một số loại chính sau đây dựa vào cách tấn công dữ liệu truyền vào:

  • Tấn công: không mã hóa kí tự nhập
  • Tấn công: không kiểm tra kiểu dữ liệu nhập

Giải thích cách tấn công SQL injection

Như đã trình bày, lỗi Sql injection thường xảy ra do hệ thống đã thiếu kiểm tra dữ liệu truyền vào. Điều này sẽ thay đổi mục đích ban đầu của câu truy vấn và do đó gây ra những tác động không mong muốn. Ta hãy xem xét câu truy vấn sau:

$query_string = "SELECT * FROM users WHERE name = '$userName'";

//Gọi thực thi truy vấn sau đó:
$sql_executer->query( $query_string );

Ta thấy rằng, mục đích chính của câu truy vấn này là lục tìm trong bảng users những dòng dữ liệu nào mà trường name có giá trị bằng với tham số userName đã truyền vào.

Thoạt nhìn thì câu truy vấn này là đúng cấu trúc và không có bất cứ vấn đề gì, thế nhưng ta hãy thử phân tích một tình huống sau đây: giả sử người gọi câu truy vấn này truyền vào tham số userName có giá trị:

somename' or '1'='1

Như vậy, sau khi ghép dữ liệu nhập vào bên trong, ta có được câu truy vấn như sau:

SELECT * FROM users WHERE name = 'somename' or '1'='1'

Các bạn có thấy không, câu truy vấn của ta giờ đã mang một ý nghĩa khác. Mệnh đề WHERE của câu truy vấn trên luôn đúng, lí do là vì '1'='1' luôn cho ra giá trị TRUE, dẫn tới câu truy vấn của ta luôn luôn thỏa điều kiện ở mệnh đề WHERE. Như vậy, thay vì trả về kết quả của MỘT dòng dữ liệu mong muốn, câu truy vấn này trả về kết quả là TOÀN BỘ dữ liệu của bảng users. Vậy là dữ liệu của hệ thống đã bị lộ.

Nguyên nhân chính của việc truy vấn sai này chính là: tấn công truyền dữ liệu vào tham số của câu truy vấn nhằm thay đổi ý nghĩa truy vấn. Hãy tưởng tượng rằng toàn bộ dữ liệu này bị sử dụng nhằm mục đích không tốt, hậu quả thật khó lường phải không nào?

Dữ liệu nhập từ người dùng là mục tiêu tấn công của SQL injection

Một số ví dụ về tấn công SQL injection

Ví dụ: dữ liệu truyền vào làm thay đổi mệnh đề điều kiện của truy vấn. Từ đây kẻ tấn công sẽ thực hiện xóa dữ liệu hệ thống

//Câu truy vấn gốc
$query_string = "SELECT * FROM users WHERE name = '$userName'";

Tham số truyền vào sẽ gây ra lỗi:

a'; DROP TABLE users;

Khi đó câu truy vấn khi bị tấn công sẽ trở thành:

SELECT * FROM users WHERE name = 'a'; DROP TABLE users;

Với ý nghĩa ban đầu là: truy vấn thông tin một user với tên được truyền vào, giờ đây câu truy vấn đã thực thi lệnh xóa bảng users. Việc này cực kì nguy hiểm.

Một số tình huống khác dễ bị tấn công SQL injection

Bất cứ thao tác nào của ứng dụng có thực thi truy vấn tới cơ sở dữ liệu đều có thể bị lợi dụng để tấn công Sql injection. Các thao tác cơ bản với CSDL là: select, insert, update đều có thể bị tấn công.

Có thể kể ra vài thao tác phổ biến để tấn công như:

  • Kiểm tra đăng nhập ứng dụng.
  • Thao tác lưu comment của user xuống DB.
  • Thao tác tìm kiếm thông tin: tên user, tên sản phẩm, …

Cách phòng tránh

Như đã phân tích ở trên: điểm để tấn công chính là tham số truyền vào câu truy vấn. Do vậy, cần phải đảm bảo thực hiện việc kiểm tra dữ liệu truyền vào từ người dùng, để tránh người dùng nhập vào những nội dung có thể gây ra sai lệch khi thực hiện truy vấn. Để kiểm tra dữ liệu từ người dùng, ta cần lọc bớt những nội dung nguy hiểm. Giải pháp cho việc lọc dữ liệu này là sử dụng chuỗi được escape (mã hóa). Lưu ý: mình sẽ dùng từ “escape” để chỉ việc mã hóa cho sát nghĩa.

Khi thực hiện escape một chuỗi, tức là mã hoá các kí tự đặc biệt của chuỗi (ví dụ như kí tự ‘, &, |, …) để nó không còn được hiểu là 1 kí tự đặc biệt nữa. Mỗi ngôn ngữ lập trình đều cung cấp các hàm để thực hiện escape chuỗi, trong PHP ta sẽ sử dụng hàm mysqli_real_escape_string() hoặc cũng có thể dùng addslashes() để thực hiện điều này.

$uname_escaped = mysqli_real_escape_string($sql_executer, $userName);
$query_string = "SELECT * FROM users WHERE name = '$uname_escaped'";

//Gọi thực thi truy vấn sau đó, dùng biến đã escaped:
$sql_executer->query( $query_string );

Tóm lại

Như vừa trình bày ở trên, lỗ hổng SQL injection thực tế không quá phức tạp và cũng không quá khó để phòng tránh. Tuy vậy, nó vẫn là một trong những lỗ hổng thường xảy ra và cũng bị nhòm ngó tấn công nhiều nhất. Lí do có thể là do lập trình viên không biết cách phòng tránh, hoặc cũng có thể do “quên” (vì cứ nghĩ là Framework đã hỗ trợ hết rồi)

Hi vọng những giải thích ở phía trên đã giúp bạn hình dung phần nào đó nguyên lí của cách tấn công này, từ đó biết cách phòng tránh để bảo vệ cho hệ thống của mình an toàn hơn.

One thought on “Sql injection – Tấn công thay đổi hoặc làm lộ CSDL hệ thống

  1. Pingback: Lỗ hổng XSS – Tấn công lấy cắp phiên đăng nhập của người dùng – Những dòng code vui

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s