SQL injection là gì? Những loại hình tấn công SQL injection điển hình

Trong phần này, chúng tôi sẽ giải thích SQL injection là gì, mô tả một số ví dụ phổ biến, giải thích cách tìm và khai thác các loại lỗ hổng SQL injection khác nhau và tóm tắt cách ngăn ngừa SQL injection.

SQL injection(SQLi) là gì?

SQL injection là một lỗ hổng bảo mật web cho phép kẻ tấn công can thiệp vào các truy vấn mà ứng dụng thực hiện đối với cơ sở dữ liệu của nó. Nó thường cho phép kẻ tấn công xem dữ liệu mà bình thường chúng không thể truy xuất. Điều này có thể chứa dữ liệu thuộc về người dùng khác hoặc bất kỳ dữ liệu nào khác mà chính ứng dụng có thể truy cập. Trong nhiều trường hợp, kẻ tấn công có thể sửa đổi hoặc xóa dữ liệu này, gây ra những thay đổi liên tục đối với nội dung hoặc hành vi của ứng dụng.

Trong một số tình huống, kẻ tấn công có thể leo thang một cuộc tấn công SQL injection để thỏa hiệp máy chủ cơ sở hoặc cơ sở hạ tầng phụ trợ khác hoặc thực hiện một cuộc tấn công từ chối dịch vụ.

Tác động của một cuộc tấn công SQL injection thành công là gì?

Một cuộc tấn công SQL injection thành công có thể dẫn đến truy cập trái phép vào dữ liệu nhạy cảm, chẳng hạn như mật khẩu, chi tiết thẻ tín dụng hoặc thông tin người dùng cá nhân. Nhiều vi phạm dữ liệu cấu hình cao trong những năm gần đây là kết quả của các cuộc tấn công SQL injection, dẫn đến thiệt hại danh tiếng và tiền phạt theo quy định. Trong một số trường hợp, kẻ tấn công có thể có được một cửa hậu liên tục vào các hệ thống của tổ chức, dẫn đến một sự thỏa hiệp lâu dài có thể không được chú ý trong một thời gian dài.

Ví dụ SQL injection

Có rất nhiều lỗ hổng SQL, các cuộc tấn công và kỹ thuật, phát sinh trong các tình huống khác nhau. Một số ví dụ SQL injection phổ biến bao gồm:

Lấy dữ liệu ẩn

Hãy xem xét một ứng dụng mua sắm hiển thị các sản phẩm trong các danh mục khác nhau. Khi người dùng nhấp vào danh mục Quà tặng, trình duyệt của họ yêu cầu URL:

https://insecure-website.com/products?carget=Gifts

Điều này khiến ứng dụng tạo một truy vấn SQL để lấy thông tin chi tiết về các sản phẩm có liên quan từ cơ sở dữ liệu:

SELECT * FROM products WHERE category = ‘Gifts’ AND released = 1

Truy vấn SQL này yêu cầu cơ sở dữ liệu trả về:

  • tất cả chi tiết (*)
  • từ bảng sản phẩm
  • trong đó danh mục là Quà tặng
  • và phát hành là 1.

Với việc released = 1 đang được sử dụng để ẩn các sản phẩm không được phát hành. Đối với các sản phẩm chưa được phát hành, có lẽ released = 0 .

Ứng dụng không thực hiện bất kỳ biện pháp phòng vệ nào trước các cuộc tấn công SQL injection, vì vậy kẻ tấn công có thể xây dựng một cuộc tấn công như:

https://insecure-website.com/products?carget=Gifts’–

Điều này dẫn đến truy vấn SQL:

SELECT * FROM products WHERE category = ‘Gifts’–‘ AND released = 1

Điều quan trọng ở đây là chuỗi dấu gạch ngang kép  là một chỉ báo nhận xét trong SQL và có nghĩa là phần còn lại của truy vấn được hiểu là một nhận xét. Điều này có hiệu quả loại bỏ phần còn lại của truy vấn, do đó, nó không còn bao gồm AND được released = 1 . Điều này có nghĩa là tất cả các sản phẩm được hiển thị, bao gồm cả các sản phẩm chưa được phát hành.

Đi xa hơn, kẻ tấn công có thể khiến ứng dụng hiển thị tất cả các sản phẩm trong bất kỳ danh mục nào, bao gồm các danh mục mà chúng không biết đến:

https://insecure-website.com/products?carget=Gifts’+OR+1=1–

Điều này dẫn đến truy vấn SQL:

SELECT * FROM products WHERE category = ‘Gifts’ OR 1=1–‘ AND released = 1

Truy vấn đã sửa đổi sẽ trả về tất cả các mục trong đó danh mục là Quà tặng hoặc 1 bằng 1. Vì 1 = 1 luôn luôn đúng, truy vấn sẽ trả về tất cả các mục.

Lật đổ logic ứng dụng

Hãy xem xét một ứng dụng cho phép người dùng đăng nhập bằng tên người dùng và mật khẩu. Nếu người dùng gửi user wiener và password bluecheese , ứng dụng sẽ kiểm tra thông tin đăng nhập bằng cách thực hiện truy vấn SQL sau:

SELECT * FROM users WHERE username = ‘wiener’ AND password = ‘bluecheese’

Nếu truy vấn trả về chi tiết của người dùng, thì đăng nhập thành công. Nếu không, nó bị từ chối.

Tại đây, kẻ tấn công có thể đăng nhập như bất kỳ người dùng nào mà không cần mật khẩu chỉ bằng cách sử dụng chuỗi nhận xét SQL  để xóa kiểm tra mật khẩu khỏi mệnh đề WHERE của truy vấn. Ví dụ: gửi quản trị viên tên người dùng  và mật khẩu trống dẫn đến truy vấn sau:

SELECT * FROM users WHERE username = ‘administrator’–‘ AND password = ”

Truy vấn này trả về người dùng có tên người dùng là quản trị viên và đăng nhập thành công kẻ tấn công với tư cách là người dùng đó.

Lấy dữ liệu từ các bảng cơ sở dữ liệu khác

Trong trường hợp kết quả của truy vấn SQL được trả về trong các phản hồi của ứng dụng, kẻ tấn công có thể tận dụng lỗ hổng SQL injection để lấy dữ liệu từ các bảng khác trong cơ sở dữ liệu. Điều này được thực hiện bằng cách sử dụng từ khóa UNION , cho phép bạn thực hiện một truy vấn CHỌN bổ sung và nối các kết quả vào truy vấn ban đầu.

Ví dụ: nếu một ứng dụng thực hiện truy vấn sau có chứa “Quà tặng” đầu vào của người dùng:

SELECT name, description FROM products WHERE category = ‘Gifts’

sau đó kẻ tấn công có thể gửi đầu vào:

‘ UNION SELECT username, password FROM users–

Điều này sẽ khiến ứng dụng trả về tất cả tên người dùng và mật khẩu cùng với tên và mô tả của sản phẩm.

Kiểm tra cơ sở dữ liệu

Sau khi xác định ban đầu một lỗ hổng SQL injection, thường rất hữu ích để có được một số thông tin về chính cơ sở dữ liệu. Thông tin này thường có thể mở đường cho việc khai thác thêm.

Bạn có thể truy vấn chi tiết phiên bản cho cơ sở dữ liệu. Cách thức này được thực hiện tùy thuộc vào loại cơ sở dữ liệu, vì vậy bạn có thể suy ra loại cơ sở dữ liệu từ bất kỳ kỹ thuật nào hoạt động. Ví dụ: trên Oracle bạn có thể thực thi:

SELECT * FROM v$version

Bạn cũng có thể xác định bảng cơ sở dữ liệu nào tồn tại và chúng chứa cột nào. Ví dụ: trên hầu hết các cơ sở dữ liệu, bạn có thể thực hiện truy vấn sau để liệt kê các bảng:

SELECT * FROM information_schema.tables

Lỗ hổng SQL injection ẩn

Nhiều trường hợp SQL injection là lỗ hổng ẩn. Điều này có nghĩa là ứng dụng không trả về kết quả của truy vấn SQL hoặc chi tiết về bất kỳ lỗi cơ sở dữ liệu nào trong các phản hồi của nó. Các lỗ hổng ẩn vẫn có thể bị khai thác để truy cập dữ liệu trái phép, nhưng các kỹ thuật liên quan thường phức tạp và khó thực hiện hơn.

Tùy thuộc vào bản chất của lỗ hổng và cơ sở dữ liệu liên quan, các kỹ thuật sau đây có thể được sử dụng để khai thác các lỗ hổng SQL injection ẩn:

  • Bạn có thể thay đổi logic của truy vấn để kích hoạt sự khác biệt có thể phát hiện được trong phản hồi của ứng dụng tùy thuộc vào sự thật của một điều kiện. Điều này có thể liên quan đến việc đưa một điều kiện mới vào một số logic Boolean hoặc gây ra một cách có điều kiện một lỗi, chẳng hạn như chia cho 0.
  • Bạn có thể kích hoạt một cách có điều kiện thời gian trễ trong quá trình xử lý truy vấn, cho phép bạn suy ra sự thật của điều kiện dựa trên thời gian mà ứng dụng cần để trả lời.
  • Bạn có thể kích hoạt tương tác mạng ngoài băng, sử dụng các kỹ thuật OAST. Kỹ thuật này cực kỳ mạnh mẽ và hoạt động trong các tình huống mà các kỹ thuật khác không làm được. Thông thường, bạn có thể trực tiếp lọc dữ liệu qua kênh ngoài băng, ví dụ bằng cách đặt dữ liệu vào tra cứu DNS cho tên miền mà bạn kiểm soát.

Cách phát hiện lỗ hổng SQL injection

Phần lớn các lỗ hổng SQL injection có thể được tìm thấy nhanh chóng và đáng tin cậy bằng cách sử dụng trình quét lỗ hổng web có sẵn trên internet.

SQL injection có thể được phát hiện thủ công bằng cách sử dụng một bộ kiểm tra có hệ thống đối với mọi điểm vào trong ứng dụng. Điều này thường bao gồm:

  • Gửi ký tự trích dẫn duy nhất  và tìm kiếm lỗi hoặc bất thường khác.
  • Đệ trình một số cú pháp dành riêng cho SQL để đánh giá giá trị cơ sở (bản gốc) của điểm nhập và đến một giá trị khác và tìm kiếm sự khác biệt có hệ thống trong các phản hồi của ứng dụng.
  • Đệ trình các điều kiện Boolean như OR 1 = 1 và OR 1 = 2 và tìm kiếm sự khác biệt trong phản hồi của ứng dụng.
  • Gửi tải trọng được thiết kế để kích hoạt độ trễ thời gian khi được thực hiện trong truy vấn SQL và tìm kiếm sự khác biệt về thời gian thực hiện để phản hồi.
  • Gửi tải trọng OAST được thiết kế để kích hoạt tương tác mạng ngoài băng khi được thực hiện trong truy vấn SQL và giám sát mọi tương tác kết quả.

SQL injection trong các phần khác nhau của truy vấn

Hầu hết các lỗ hổng SQL injection phát sinh trong mệnh đề WHERE của truy vấn SELECT . Kiểu tấn công này thường được hiểu rõ bởi những người thử nghiệm có kinh nghiệm.

Nhưng về nguyên tắc, các lỗ hổng SQL injection có thể xảy ra tại bất kỳ vị trí nào trong truy vấn và trong các loại truy vấn khác nhau. Các vị trí phổ biến nhất khác nơi SQL SQL phát sinh là:

  • Trong các câu lệnh UPDATE , trong các giá trị được cập nhật hoặc mệnh đề WHERE .
  • Trong các câu lệnh INSERT , trong các giá trị được chèn.
  • Trong các câu lệnh SELECT , trong tên bảng hoặc cột.
  • Trong các câu lệnh SELECT, trong mệnh đề ORDER BY .

Cách ngăn ngừa SQL injection

Hầu hết các trường hợp tấn công SQL injection có thể được ngăn chặn bằng cách sử dụng các truy vấn được tham số hóa (còn được gọi là câu lệnh đã chuẩn bị) thay vì nối chuỗi trong truy vấn.

Đoạn mã sau dễ bị tấn công SQL vì đầu vào của người dùng được nối trực tiếp vào truy vấn:

String query = "SELECT * FROM products WHERE category = '"+ input + "'";

Statement statement = connection.createStatement();

ResultSet resultSet = statement.executeQuery(query);

Mã này có thể dễ dàng được viết lại theo cách ngăn chặn đầu vào của người dùng can thiệp vào cấu trúc truy vấn:

PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");

statement.setString(1, input);

ResultSet resultSet = statement.executeQuery();

Các truy vấn được tham số hóa có thể được sử dụng cho mọi tình huống trong đó đầu vào không tin cậy xuất hiện dưới dạng dữ liệu trong truy vấn, bao gồm mệnh đề WHERE và các giá trị trong câu lệnh INSERT hoặc UPDATE . Chúng không thể được sử dụng để xử lý đầu vào không đáng tin cậy trong các phần khác của truy vấn, chẳng hạn như tên bảng hoặc cột hoặc mệnh đề ORDER BY . Chức năng ứng dụng đặt dữ liệu không đáng tin cậy vào các phần của truy vấn sẽ cần thực hiện một cách tiếp cận khác, chẳng hạn như liệt kê các giá trị đầu vào được phép liệt kê trắng hoặc sử dụng logic khác nhau để đưa ra hành vi cần thiết.

Để một truy vấn được tham số hóa có hiệu quả trong việc ngăn chặn SQL injection, chuỗi được sử dụng trong truy vấn phải luôn là một hằng số được mã hóa cứng và không bao giờ được chứa bất kỳ dữ liệu biến nào từ bất kỳ nguồn gốc nào. Không nên quyết định từng trường hợp cụ thể liệu một mục dữ liệu có đáng tin cậy hay không và tiếp tục sử dụng nối chuỗi trong truy vấn cho các trường hợp được coi là an toàn. Tất cả đều quá dễ dàng để phạm sai lầm về nguồn gốc dữ liệu có thể, hoặc cho những thay đổi trong mã khác vi phạm các giả định về những gì dữ liệu bị ô nhiễm.

bình luận

Leave a Comment