SecOps Portal
Trang chủ › Nghiên Cứu Bảo Mật

Tìm hiểu về lỗ hổng SQL Injection và cách khắc phục

Ban biên tập SecOps Portal · · Cập nhật
Tìm hiểu về lỗ hổng SQL Injection và cách khắc phục

SQL Injection là lỗ hổng xảy ra khi ứng dụng ghép trực tiếp dữ liệu người dùng vào câu lệnh SQL, khiến kẻ tấn công thay đổi được ý nghĩa của truy vấn. Cách khắc phục cốt lõi là dùng truy vấn tham số hóa (prepared statement) ở mọi nơi, để cơ sở dữ liệu luôn hiểu dữ liệu là dữ liệu chứ không phải một phần của lệnh. Kết hợp thêm kiểm tra đầu vào, tài khoản cơ sở dữ liệu quyền tối thiểu và không hiển thị lỗi SQL cho người dùng để giảm rủi ro và thiệt hại.

Nguyên nhân gốc của SQL Injection

Hãy hình dung đoạn mã kiểm tra đăng nhập tạo câu truy vấn bằng cách nối chuỗi: lấy tên đăng nhập người dùng nhập vào, đặt giữa hai dấu nháy trong câu SELECT. Nếu người dùng nhập tên bình thường, mọi thứ ổn. Nhưng nếu dữ liệu nhập vào chứa dấu nháy và một đoạn cú pháp SQL, đoạn đó trở thành một phần của câu lệnh. Cơ sở dữ liệu không có cách nào biết phần nào do lập trình viên viết, phần nào do người dùng gửi.

Vấn đề không nằm ở ký tự đặc biệt cụ thể nào, mà ở việc trộn lẫn mã và dữ liệu trong cùng một chuỗi. Đây là cùng một gốc rễ với các lỗi injection khác như chèn lệnh hệ điều hành hay XSS.

Hậu quả có thể xảy ra

  • Vượt qua đăng nhập mà không cần mật khẩu.
  • Đọc dữ liệu không được phép: thông tin khách hàng, mã băm mật khẩu, đơn hàng.
  • Sửa hoặc xóa dữ liệu.
  • Trong cấu hình kém, thực thi lệnh trên máy chủ cơ sở dữ liệu hoặc đọc tệp hệ thống.
  • Làm chậm hoặc sập cơ sở dữ liệu.

Nhiều vụ rò rỉ dữ liệu lớn trong lịch sử bắt nguồn từ SQL Injection, dù đây là lỗi đã được biết đến và có cách phòng chống rõ ràng từ lâu.

Các dạng SQL Injection

DạngĐặc điểm
In-band (dựa trên lỗi, UNION)Kết quả hoặc thông báo lỗi hiển thị trực tiếp trên trang
Blind dựa trên booleanKhông thấy dữ liệu, nhưng trang phản hồi khác nhau khi điều kiện đúng hoặc sai
Blind dựa trên thời gianSuy ra thông tin qua độ trễ phản hồi
Out-of-bandDữ liệu bị gửi ra ngoài qua kênh khác như DNS
Second-orderDữ liệu độc được lưu trước, gây lỗi ở truy vấn khác sau đó

Dạng second-order đáng chú ý vì lập trình viên thường tin dữ liệu đã nằm trong cơ sở dữ liệu là "sạch". Nguyên tắc đúng: mọi dữ liệu ghép vào truy vấn đều phải tham số hóa, bất kể đến từ đâu.

Khắc phục 1: Truy vấn tham số hóa

Với prepared statement, câu truy vấn được gửi tới cơ sở dữ liệu với các chỗ giữ chỗ (placeholder), dữ liệu được gửi riêng. Cơ sở dữ liệu phân tích cấu trúc câu lệnh trước, sau đó mới gắn dữ liệu vào, nên dữ liệu không bao giờ thay đổi được cấu trúc. Mọi ngôn ngữ và thư viện truy cập cơ sở dữ liệu phổ biến đều hỗ trợ cách này.

Lưu ý: placeholder chỉ dùng cho giá trị. Tên bảng, tên cột, từ khóa sắp xếp (ASC/DESC) không tham số hóa được; với những chỗ này, dùng danh sách cho phép cố định trong mã và ánh xạ từ lựa chọn của người dùng.

Khắc phục 2: Dùng ORM đúng cách

ORM tự sinh truy vấn tham số hóa khi dùng API thông thường. Rủi ro xuất hiện khi lập trình viên dùng các hàm truy vấn thô (raw query) và ghép chuỗi vào đó. Rà soát mọi chỗ dùng truy vấn thô trong dự án.

Khắc phục 3: Stored procedure an toàn

Stored procedure giúp tách logic, nhưng chỉ an toàn khi bên trong không ghép chuỗi để tạo SQL động. Một stored procedure dùng EXEC với chuỗi nối từ tham số vẫn bị injection như thường.

Các lớp bảo vệ bổ sung

  • Kiểm tra đầu vào: ID phải là số, email đúng định dạng, độ dài giới hạn. Không thay thế tham số hóa nhưng giảm bề mặt tấn công.
  • Quyền tối thiểu: tài khoản ứng dụng chỉ có quyền đọc ghi trên bảng cần thiết; không dùng tài khoản quản trị, không quyền đọc tệp hay thực thi lệnh hệ thống.
  • Ẩn thông báo lỗi: lỗi SQL chi tiết chỉ ghi vào log nội bộ.
  • Tường lửa ứng dụng web (WAF): chặn mẫu tấn công phổ biến, hữu ích như lớp tạm thời nhưng có thể bị vượt qua.
  • Mã hóa dữ liệu nhạy cảm, băm mật khẩu đúng cách: giảm giá trị dữ liệu nếu bị đọc trộm; xem bài cơ chế băm mật khẩu bcrypt.

Quyền tối thiểu không chỉ áp dụng cho tài khoản ứng dụng mà cho cả con người truy cập dữ liệu. Cách tổ chức phân quyền này được bàn trong bài quản lý quyền truy cập dữ liệu nhạy cảm.

Phát hiện SQL Injection trong ứng dụng của bạn

  1. Tìm trong mã nguồn mọi chỗ tạo truy vấn bằng nối chuỗi hoặc định dạng chuỗi có biến.
  2. Dùng công cụ phân tích mã tĩnh để tự động đánh dấu mẫu nguy hiểm.
  3. Thử nhập ký tự đặc biệt vào tham số trên môi trường thử nghiệm và quan sát lỗi 500, phản hồi khác thường.
  4. Theo dõi log: yêu cầu chứa từ khóa SQL đi kèm lỗi máy chủ; xem bài phân tích log máy chủ.

Chỉ kiểm thử trên ứng dụng bạn sở hữu hoặc được ủy quyền.

Khi phát hiện lỗ hổng đã bị khai thác

  • Vá lỗi ngay bằng tham số hóa, không chỉ chặn chuỗi tấn công cụ thể.
  • Xác định dữ liệu nào có thể đã bị truy cập qua log ứng dụng và log cơ sở dữ liệu.
  • Đổi mật khẩu tài khoản cơ sở dữ liệu, thu hồi khóa có thể đã lộ.
  • Nếu mã băm mật khẩu người dùng có thể đã lộ, yêu cầu đặt lại mật khẩu.
  • Thực hiện nghĩa vụ thông báo theo quy định về bảo vệ dữ liệu cá nhân nếu áp dụng.

SQL Injection là ví dụ kinh điển cho nhóm Injection trong OWASP Top 10, và bài học từ nó áp dụng cho mọi nơi dữ liệu gặp trình thông dịch.

Câu hỏi thường gặp

Dùng hàm escape chuỗi có đủ chống SQL Injection không?

Escape thủ công dễ sai, phụ thuộc bộ ký tự và ngữ cảnh, và không áp dụng được cho giá trị số không đặt trong dấu nháy. Truy vấn tham số hóa là cách được khuyến nghị.

Cơ sở dữ liệu NoSQL có bị injection không?

Có. NoSQL không dùng cú pháp SQL nhưng vẫn có thể bị chèn toán tử truy vấn nếu ứng dụng đưa đối tượng do người dùng gửi thẳng vào truy vấn. Nguyên tắc vẫn là kiểm tra kiểu dữ liệu và không trộn dữ liệu với cấu trúc truy vấn.

WAF có thay thế được việc sửa mã không?

Không. WAF là lớp bảo vệ bổ sung, có thể chặn tấn công phổ biến trong lúc chờ vá, nhưng kẻ tấn công có nhiều kỹ thuật vượt qua. Sửa tận gốc trong mã mới là giải pháp lâu dài.

ORM có hoàn toàn miễn nhiễm SQL Injection?

Không hoàn toàn. ORM an toàn khi dùng API chuẩn, nhưng các hàm truy vấn thô, sắp xếp theo tên cột do người dùng gửi hoặc một số tính năng nâng cao vẫn có thể bị injection nếu dùng sai.

Bài liên quan