TL; DR
- Ứng dụng chấp nhận đầu vào, trong trường hợp này là 'Nancy', mà không cố gắng - vệ sinh đầu vào, chẳng hạn như bằng cách thoát
trường ký tự đặc biệt => XÁC NHẬN VÀO học sinh GIÁ TRỊ ( 'Nancy' ); XÁC NHẬN 0 1
- Lỗi SQL xảy ra khi đầu vào vào lệnh cơ sở dữ liệu bị thao túng - khiến máy chủ cơ sở dữ liệu thực thi
trường SQL tùy ý => XÁC NHẬN VÀO sinh viên GIÁ TRỊ ( 'Robert' ); Học sinh DROP BẢNG ; - '); INSERT 0 1 thả TABLE
- Hồ sơ học sinh đã biến mất - nó thậm chí còn tồi tệ hơn!
trường học => CHỌN * TỪ học sinh ;
LỖI : mối quan hệ "sinh viên" không không tồn tại
LINE 1 : CHỌN * TỪ học sinh ; ^
Điều này làm giảm (xóa) bảng sinh viên.
( Tất cả các ví dụ mã trong câu trả lời này đã được chạy trên máy chủ cơ sở dữ liệu PostgreSQL 9.1.2. )
Để làm rõ những gì đang xảy ra, hãy thử điều này với một bảng đơn giản chỉ chứa trường tên và thêm một hàng:
trường => CREATE TABLE sinh viên ( tên TEXT TIỂU KEY );
THÔNG BÁO : CREATE TABLE / TIỂU KEY sẽ tạo tiềm ẩn chỉ số "students_pkey" cho bảng "sinh viên" CREATE TABLE
trường
=> CHÈN VÀO sinh viên GIÁ TRỊ ( 'John' ); XÁC NHẬN 0 1
Giả sử ứng dụng sử dụng SQL sau để chèn dữ liệu vào bảng:
XÁC NHẬN VÀO sinh viên GIÁ TRỊ ( 'foobar' );
Thay thế foobar
bằng tên thật của học sinh. Một hoạt động chèn bình thường sẽ trông như thế này:
- Đầu vào:
trường Nancy => XÁC NHẬN VÀO học sinh GIÁ TRỊ ( 'Nancy' ); XÁC NHẬN 0 1
Khi chúng tôi truy vấn bảng, chúng tôi nhận được điều này:
trường học => CHỌN * TỪ học sinh ;
Tên
-------
John
Nancy
( 2 hàng )
Điều gì xảy ra khi chúng ta chèn tên của Little Bobby Table vào bảng?
- Đầu vào: Robert '); Học sinh DROP BẢNG; -
trường học => XÁC NHẬN VÀO sinh viên GIÁ TRỊ ( 'Robert' ); Học sinh DROP BẢNG ; - ');
INSERT 0 1 thả TABLE
Việc tiêm SQL ở đây là kết quả của tên của sinh viên chấm dứt câu lệnh và bao gồm một DROP TABLE
lệnh riêng ; hai dấu gạch ngang ở cuối đầu vào được dự định để nhận xét bất kỳ mã còn sót lại nào có thể gây ra lỗi. Dòng cuối cùng của đầu ra xác nhận rằng máy chủ cơ sở dữ liệu đã bỏ bảng.
Điều quan trọng cần lưu ý là trong quá trình INSERT
hoạt động, ứng dụng không kiểm tra đầu vào cho bất kỳ ký tự đặc biệt nào và do đó cho phép nhập dữ liệu tùy ý vào lệnh SQL. Điều này có nghĩa là người dùng độc hại có thể chèn, vào một trường thường dành cho đầu vào của người dùng, các ký hiệu đặc biệt như dấu ngoặc kép cùng với mã SQL tùy ý để khiến hệ thống cơ sở dữ liệu thực thi nó, do đó SQL bị tiêm .
Kết quả?
trường học => CHỌN * TỪ học sinh ;
LỖI : mối quan hệ "sinh viên" không không tồn tại
LINE 1 : CHỌN * TỪ học sinh ; ^
SQL tiêm là cơ sở dữ liệu tương đương với lỗ hổng thực thi mã tùy ý từ xa trong một hệ điều hành hoặc ứng dụng. Tác động tiềm tàng của một cuộc tấn công SQL SQL thành công không thể được đánh giá thấp - tùy thuộc vào hệ thống cơ sở dữ liệu và cấu hình ứng dụng, kẻ tấn công có thể sử dụng nó để gây mất dữ liệu (như trong trường hợp này), truy cập trái phép vào dữ liệu hoặc thậm chí thực thi mã tùy ý trên chính máy chủ.
Như truyện tranh XKCD đã lưu ý, một cách để bảo vệ chống lại các cuộc tấn công SQL SQL là vệ sinh các đầu vào cơ sở dữ liệu, chẳng hạn như thoát các ký tự đặc biệt, để chúng không thể sửa đổi lệnh SQL cơ bản và do đó không thể thực thi mã SQL tùy ý. Nếu bạn sử dụng các truy vấn được tham số hóa, chẳng hạn như bằng cách sử dụng SqlParameter
trong ADO.NET, tối thiểu, đầu vào sẽ được tự động vệ sinh để bảo vệ chống lại việc tiêm SQL.
Tuy nhiên, vệ sinh đầu vào ở cấp ứng dụng có thể không dừng các kỹ thuật tiêm SQL nâng cao hơn. Ví dụ, có nhiều cách để phá vỡ mysql_real_escape_string
hàm PHP . Để bảo vệ thêm, nhiều hệ thống cơ sở dữ liệu hỗ trợ các câu lệnh được chuẩn bị . Nếu được triển khai đúng cách trong phần phụ trợ, các câu lệnh được chuẩn bị có thể khiến SQL tiêm không thể thực hiện được bằng cách xử lý các đầu vào dữ liệu tách biệt về mặt ngữ nghĩa với phần còn lại của lệnh.