SQL Injection 101: SQLi là gì và cách ngăn chặn các cuộc tấn công
Tháng 8 06, 2022 • bảo mật
SQL injection là gì
SQL injection (SQLi) là một loại tấn công cho phép tội phạm thực thi các câu lệnh SQL độc hại chống lại các ứng dụng web dễ bị tổn thương. Kẻ tấn công có thể truy cập dữ liệu nhạy cảm, chẳng hạn như thông tin khách hàng, dữ liệu cá nhân, bí mật thương mại và nhiều hơn nữa bằng cách vượt qua các biện pháp bảo mật của ứng dụng. Ở đây chúng ta sẽ thảo luận về SQL injection, cách nó hoạt động và cách bạn có thể ngăn chặn các cuộc tấn công.
Các cuộc tấn công SQL injection có thể xảy ra trên bất kỳ trang web nào sử dụng cơ sở dữ liệu SQL. Loại tấn công này cho phép kẻ tấn công truy cập vào dữ liệu quan trọng của bạn. Họ có thể xem thông tin người tiêu dùng, dữ liệu cá nhân, bí mật thương mại và tài sản trí tuệ. Đây là một trong những loại tấn công nghiêm trọng nhất trên các ứng dụng web, theo OWASP.
Các loại SQL Injection

In-band SQLi
In-band SQL injection là một cuộc tấn công mà kẻ tấn công sử dụng cùng một kênh để gửi và nhận truy vấn. In-band có nghĩa là phản hồi được nhận bằng cách sử dụng cùng một phương tiện truyền thông. Mục tiêu của kẻ tấn công là nhận được phản hồi trong trình duyệt web ngay lập tức, nếu có thể khi thực hiện cuộc tấn công thủ công với trình duyệt web.
Ví dụ về in-band SQL injection
Cách phổ biến nhất để kẻ tấn công thực hiện in-band SQL injection là thay đổi yêu cầu để họ có thể xem thông tin cá nhân của người dùng hiện tại. Điều này có thể được thực hiện bằng cách thay đổi giá trị được gửi như một phần của yêu cầu. Ví dụ, nếu câu lệnh được cho là hiển thị tên của người dùng, kẻ tấn công có thể thay đổi nó để tên của họ được hiển thị thay thế.
SELECT * FROM users WHERE user_id LIKE 'current_user'
Error-based SQLi và Union-based SQLi là hai hình thức phổ biến nhất của in-band SQL injection.
Error-based SQLi
Kỹ thuật SQLi dựa trên lỗi là một phương pháp in-band SQL injection lợi dụng các thông báo lỗi của máy chủ cơ sở dữ liệu để khám phá kiến trúc của cơ sở dữ liệu. SQL injection dựa trên lỗi là loại phổ biến nhất của in-band SQL injection.
Ví dụ về error-based SQLi:
Nếu một kẻ tấn công cố gắng đăng nhập với các thông tin sau:
username: ' OR 'a'='apassword: bất kỳ
Cơ sở dữ liệu sẽ trả về một lỗi vì câu lệnh không đúng cú pháp. Thông báo lỗi sẽ tiết lộ thông tin về cơ sở dữ liệu, mà kẻ tấn công có thể sử dụng để lợi dụng.
Union-based SQLi:
In-band SQL injection là một cách để lấy thông tin từ một trang web bằng cách sử dụng toán tử UNION để kết hợp kết quả của hai hoặc nhiều câu lệnh SELECT.
Blind SQL injection
Blind SQL injection là một cuộc tấn công mà kẻ tấn công cố gắng lấy câu trả lời từ cơ sở dữ liệu bằng cách đặt câu hỏi sẽ dẫn đến một phản hồi đúng hoặc sai. Kẻ tấn công sử dụng thông báo lỗi để xem liệu ứng dụng có phản hồi khác nhau khi một mã cụ thể được sử dụng hay không.
Khi một hacker sử dụng SQL injection, ứng dụng web có thể hiển thị các thông báo cảnh báo cơ sở dữ liệu quan trọng cho biết rằng cú pháp truy vấn SQL không đúng. Blind SQL injection hoạt động giống như SQL injection truyền thống, ngoại trừ cách dữ liệu được lấy từ cơ sở dữ liệu. Nếu một cơ sở dữ liệu không có đủ thông tin để kẻ tấn công lợi dụng, kẻ tấn công phải đặt một loạt câu hỏi để lấy dữ liệu.
Blind SQL injection được chia thành blind-boolean-based SQLi và Blind-time-based SQLi.
Boolean-based Blind SQLi
Boolean-based Blind SQL injection là một cuộc tấn công mà kẻ tấn công cố gắng lấy câu trả lời từ cơ sở dữ liệu bằng cách đặt câu hỏi sẽ dẫn đến một phản hồi đúng hoặc sai. Kẻ tấn công sử dụng thông báo lỗi để xem liệu ứng dụng có phản hồi khác nhau khi một mã cụ thể được sử dụng hay không.
Ví dụ về boolean-based Blind SQLi:
Nếu một kẻ tấn công muốn tìm ra loại cơ sở dữ liệu, họ sẽ sử dụng câu lệnh sau:
SELECT * FROM users WHERE user_id LIKE 'current_user' and database() like '%type%'
Nếu cơ sở dữ liệu là MySQL, kết quả sẽ giống như sau:
Bạn có lỗi trong cú pháp SQL của mình; hãy kiểm tra hướng dẫn tương ứng với phiên bản máy chủ MySQL của bạn để sử dụng cú pháp đúng gần ‘and database() like ‘%type%” tại dòng
Time-based Blind SQL injection
Một cuộc tấn công Blind dựa trên thời gian là khi một lệnh SQL được gửi đến máy chủ với mã khiến các truy vấn thực thi chậm hơn.
Các cuộc tấn công Blind dựa trên thời gian cho phép kẻ tấn công trích xuất dữ liệu dựa trên thời gian truy cập. Một cuộc tấn công như vậy được gọi là một cuộc tấn công tiêm mù hoặc suy luận. Đây là một loại tấn công mà không có dữ liệu nào chảy giữa kẻ tấn công và cơ sở dữ liệu, nhưng vì không có phản hồi, nó cũng được gọi là một cuộc tấn công tiêm mù.
Thời gian phản hồi cho biết liệu câu trả lời có đúng hay không. Nếu phản hồi là tiêu cực, kẻ xâm nhập sẽ thực hiện một yêu cầu khác. Kỹ thuật tấn công này chậm vì hacker phải đi qua từng ký tự một cách riêng lẻ, đặc biệt là khi tấn công các cơ sở dữ liệu lớn.
Ví dụ về blind SQLi
Trong ví dụ này, kẻ tấn công cố gắng xác định xem người dùng có id=999 có tồn tại trong cơ sở dữ liệu hay không. Để làm điều này, họ sử dụng câu lệnh sau:
IF(SUBSTRING((SELECT password FROM users WHERE user_id=999),0, LEN('secret'))='secret', SLEEP(30), 'false')
Nếu người dùng có id 999 tồn tại trong cơ sở dữ liệu và mật khẩu của họ là secret, thì ứng dụng sẽ ngủ trong 30 giây. Ứng dụng sẽ trả về false nếu người dùng không tồn tại trong cơ sở dữ liệu.
Out-of-band SQLi
Ai đó muốn đánh cắp dữ liệu có thể gửi mã SQL đến máy chủ cơ sở dữ liệu theo cách không phải là một phần của giao tiếp thông thường giữa máy chủ và các máy tính khác. Điều này có thể được thực hiện bằng cách gửi thông tin đến máy chủ thông qua các yêu cầu DNS hoặc HTTP.
Phản hồi của ứng dụng sẽ không bị ảnh hưởng bởi việc có hay không có dữ liệu nào được trả về, có hay không có vấn đề với cơ sở dữ liệu, hoặc mất bao lâu để thực thi truy vấn. Out-of-band có thể được sử dụng trong các tương tác mạng để kích hoạt các sự kiện theo ý muốn. Tùy thuộc vào điều kiện được tiêm, chúng có thể được kích hoạt có điều kiện để thu thập kiến thức từng chút một.
Dữ liệu cũng có thể rò rỉ thông qua một số giao thức mạng từ các tương tác mạng. Hình ảnh đại diện cho yêu cầu được gửi từ ứng dụng web đến cơ sở dữ liệu của ứng dụng.
Ví dụ về out-of-band SQLi
Trong ví dụ này, kẻ tấn công cố gắng xác định xem một người dùng cụ thể có tồn tại trong cơ sở dữ liệu hay không. Để làm điều này, họ sử dụng câu lệnh sau:
SELECT user_id FROM users WHERE username='$username' AND password='$password' LIMIT 0,0 UNION SELECT NULL,'' INTO OUTFILE '/var/opt/databases/$filename.php'; --
Ứng dụng sẽ trả về ID người dùng của họ nếu người dùng tồn tại trong cơ sở dữ liệu. Nếu người dùng không tồn tại trong cơ sở dữ liệu, thì ứng dụng sẽ tạo một tệp chứa mã PHP có thể được sử dụng để thực thi các lệnh hệ thống. Kẻ tấn công sau đó có thể sử dụng tệp này để chạy các lệnh trên máy chủ.
Cách ngăn chặn SQL injection
Cách tốt nhất để bảo vệ chống lại các cuộc tấn công SQL injection là sử dụng xác thực đầu vào, câu lệnh chuẩn bị sẵn và truy vấn có tham số. Mã không bao giờ nên sử dụng trực tiếp đầu vào của người dùng. Các nhà phát triển phải làm sạch tất cả đầu vào thay vì chỉ các đầu vào từ biểu mẫu web như biểu mẫu đăng nhập. Dấu nháy đơn nên được loại bỏ khỏi bất kỳ thành phần mã đáng ngờ nào. Cũng là một ý tưởng tốt để ẩn các vấn đề cơ sở dữ liệu trên các trang web trực tiếp để tránh vô tình tiết lộ chúng. SQL injection có thể cung cấp thông tin về hệ thống cơ sở dữ liệu mà kẻ tấn công có thể sử dụng để lợi dụng.
Nếu bạn phát hiện vấn đề với trang web của mình, bạn nên đưa nó offline ngay lập tức và liên hệ với nhà cung cấp dịch vụ lưu trữ của bạn. Họ có thể giúp bạn xác định liệu trang web của bạn có bị xâm phạm hay không và những bước bạn cần thực hiện để khắc phục vấn đề. Trong thời gian chờ đợi, hãy đảm bảo rằng tất cả người dùng của trang web của bạn biết về vấn đề và thay đổi mật khẩu của họ càng sớm càng tốt.
Mẹo phòng ngừa để tránh SQL injection
Có một vài cách để tránh các lỗ hổng SQL injection trong ngôn ngữ lập trình và thiết lập cơ sở dữ liệu của bạn. Những kỹ thuật này có thể được sử dụng với hầu hết các cơ sở dữ liệu, chẳng hạn như XML. Bạn có thể sử dụng những kỹ thuật này để làm cho cơ sở dữ liệu của bạn an toàn hơn.
1) Sử dụng các thủ tục lưu trữ được xây dựng đúng cách
Người mới bắt đầu nên bắt đầu bằng cách học cách tạo các câu lệnh với biến. Điều này dễ hơn so với tạo các truy vấn động và dễ hiểu hơn. Truy vấn có tham số là nơi nhà phát triển tạo tất cả mã SQL và sau đó cung cấp từng tham số vào một ngày sau đó. Phương pháp này cho phép cơ sở dữ liệu xác định giữa mã nguồn và thông tin.
Các câu lệnh chuẩn bị sẵn giúp đảm bảo rằng mục tiêu của một truy vấn không bị thay đổi, ngay cả khi ai đó cố gắng đưa ra các chỉ dẫn SQL.
2) Xác thực đầu vào danh sách cho phép
Các truy vấn SQL sử dụng các biến liên kết ở các vị trí cụ thể cho dữ liệu. Ví dụ, nếu bạn đang sử dụng Python, bạn sẽ sử dụng %s chỗ trống. Bạn có thể sử dụng một biểu thức chính quy để xác thực đầu vào của người dùng so với danh sách cho phép cho các ký tự nào được phép trong từng biến liên kết.
Nếu bạn đang sử dụng JavaScript, bạn có thể sử dụng \w để khớp các ký tự chữ và số và dấu gạch dưới.
Danh sách cho phép nên cụ thể nhất có thể để tránh các kết quả dương tính giả.
Ví dụ, nếu bạn đang tìm kiếm một số điện thoại Hoa Kỳ, bạn sẽ sử dụng biểu thức chính quy sau:
/^\d{11}$/
Điều này sẽ khớp với một chuỗi gồm 11 chữ số có thể là một số điện thoại. Nếu ai đó cố gắng gửi một cái gì đó như ‘abcdef‘, nó sẽ không khớp và đầu vào sẽ không hợp lệ.
Điều này sẽ giúp đảm bảo dữ liệu của bạn an toàn và bảo mật. Nếu bạn cần sử dụng các giá trị từ mã thay vì các tham số người dùng, điều đó cũng không sao!
Tuy nhiên, giả sử các giá trị tham số người dùng nhắm mục tiêu đến các tên bảng và cột cụ thể. Trong trường hợp đó, các giá trị tham số nên được ánh xạ tới các tên bảng và cột tương ứng để đảm bảo rằng đầu vào của người dùng không được xác thực không đi vào truy vấn.
3) Sử dụng danh sách trắng
Đừng lọc đầu vào của người dùng dựa trên danh sách đen của các ký tự xấu. Sử dụng danh sách cho phép các ký tự tốt được mong đợi trong các trường cụ thể hiệu quả hơn nhiều. Điều này sẽ ngăn chặn các cuộc tấn công SQL injection trước khi chúng bắt đầu.
Ví dụ, chỉ cho phép các chữ số và dấu gạch ngang trong trường đầu vào nếu bạn mong đợi một số điện thoại. Nếu bạn đang mong đợi một địa chỉ email, chỉ cho phép các ký tự hợp lệ trong một địa chỉ email.
4) Sử dụng các nền tảng mới nhất
PHP không có bảo vệ SQLi trong các nền tảng phát triển web cũ hơn. Sử dụng phiên bản mới nhất của môi trường lập trình, ngôn ngữ và các công nghệ liên quan có sẵn. Thay vì PHP, hãy sử dụng PDO trong ví dụ này.
5) Quét ứng dụng web của bạn thường xuyên
SQL injections có thể rất khó phát hiện. Điều quan trọng là quét ứng dụng web của bạn để tìm các lỗ hổng thường xuyên.
6) Thực thi nguyên tắc quyền tối thiểu
Nguyên tắc quyền tối thiểu là một khái niệm bảo mật hạn chế người dùng chỉ có quyền truy cập tối thiểu cần thiết để thực hiện công việc của họ. Điều này bao gồm việc hạn chế số lượng tài khoản mà người dùng có và các quyền mà các tài khoản đó có.
Hạn chế tối thiểu về chức năng (LRF) là thực hành và khái niệm hạn chế quyền của người dùng, tài khoản và quy trình tính toán chỉ đối với những tài nguyên cần thiết cho các nhiệm vụ cơ bản, chấp nhận được. Điều này giúp duy trì quyền hoặc mức độ truy cập tối thiểu của người dùng, điều này rất quan trọng để mọi người thực hiện công việc của họ hiệu quả.
Quyền tối thiểu là một nguyên tắc bảo mật yêu cầu các ứng dụng, hệ thống và thiết bị chỉ có các quyền cần thiết để hoàn thành một nhiệm vụ cụ thể. Bằng cách này, tác động sẽ bị giới hạn nếu ai đó quản lý để khai thác một lỗ hổng và gây thiệt hại. Điều này trái ngược với việc cho người dùng nhiều quyền hơn họ cần, điều này làm tăng nguy cơ gây hại đáng kể trong một cuộc tấn công SQL.
SQL Injection – Câu hỏi thường gặp
In-band SQL injection là loại tấn công SQL injection phổ biến nhất. Nó xảy ra khi kẻ tấn công có thể sử dụng cùng một kênh truyền thông để gửi payload và thu thập kết quả.
Phòng thủ tốt nhất chống lại SQL injection là sử dụng truy vấn có tham số. Loại truy vấn này sử dụng các giá trị chỗ trống cho các tham số, được cung cấp vào một ngày sau đó. Phương pháp này cho phép cơ sở dữ liệu xác định giữa mã nguồn và thông tin.
SQL injection có thể được phát hiện theo nhiều cách. Một phương pháp là sử dụng tường lửa ứng dụng web (WAF). WAF là một phần cứng hoặc phần mềm nằm giữa một ứng dụng web và internet. Nó kiểm tra lưu lượng truy cập để tìm hoạt động độc hại và có thể chặn các cuộc tấn công SQL injection.
SQL injection thứ cấp xảy ra khi kẻ tấn công có thể tiêm một payload được lưu trữ bởi ứng dụng web và sau đó được thực thi sau đó. Loại tấn công này khó đạt được hơn vì kẻ tấn công phải có cách kích hoạt việc thực thi payload được lưu trữ.
Blind SQL injection là một cuộc tấn công mà kẻ tấn công không trực tiếp thấy kết quả của payload của họ. Thay vào đó, họ phải sử dụng các câu lệnh đúng hoặc sai để suy luận thông tin từ cơ sở dữ liệu. Loại tấn công này khó thực hiện hơn nhưng có thể nguy hiểm như các loại SQL injection khác.
Truy vấn xếp chồng là một loại SQL injection mà kẻ tấn công sử dụng nhiều truy vấn để trích xuất thông tin từ cơ sở dữ liệu. Loại tấn công này khó thực hiện hơn nhưng có thể rất nguy hiểm nếu thành công.
SQL injection dựa trên lỗi là một cuộc tấn công mà kẻ tấn công sử dụng các lỗi cơ sở dữ liệu để suy luận thông tin từ cơ sở dữ liệu. Cuộc tấn công này khó thực hiện hơn nhưng có thể rất nguy hiểm nếu thành công.
bảo vệ
admin là một biên tập viên cấp cao của Government Technology. Trước đây cô đã viết cho PYMNTS và The Bay State Banner, và có bằng Cử nhân Nghệ thuật sáng tác của trường Carnegie Mellon. Cô sống ở ngoại ô Boston.