Các thủ tục được lưu trữ không ngăn chặn phép tiêm SQL một cách kỳ diệu, nhưng chúng làm cho việc ngăn chặn nó trở nên dễ dàng hơn rất nhiều. Tất cả bạn phải làm là một cái gì đó như sau (ví dụ Postgres):
CREATE OR REPLACE FUNCTION my_func (
IN in_user_id INT
)
[snip]
SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]
Đó là nó! Vấn đề chỉ xuất hiện khi hình thành một truy vấn thông qua nối chuỗi (tức là SQL động) và thậm chí trong những trường hợp đó bạn có thể liên kết được! (Phụ thuộc vào cơ sở dữ liệu.)
Cách tránh SQL tiêm trong truy vấn động của bạn:
Bước 1) Tự hỏi nếu bạn thực sự cần một truy vấn động. Nếu bạn gắn các chuỗi lại với nhau chỉ để đặt đầu vào, thì có lẽ bạn đã làm sai. (Có các trường hợp ngoại lệ cho quy tắc này - một ngoại lệ là báo cáo truy vấn trên một số cơ sở dữ liệu, bạn có thể gặp vấn đề về hiệu năng nếu bạn không buộc nó biên dịch một truy vấn mới với mỗi lần thực hiện. )
Bước 2) Nghiên cứu cách thích hợp để đặt biến cho RDBMS cụ thể của bạn. Ví dụ, Oracle cho phép bạn thực hiện các thao tác sau (trích dẫn từ tài liệu của họ):
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!
Ở đây bạn vẫn không nối đầu vào. Bạn đang ràng buộc một cách an toàn! Hoan hô!
Nếu cơ sở dữ liệu của bạn không hỗ trợ một cái gì đó như ở trên (hy vọng không ai trong số chúng vẫn tệ như vậy, nhưng tôi sẽ không ngạc nhiên) - hoặc nếu bạn vẫn thực sự phải nối dữ liệu đầu vào của mình (như trong trường hợp "đôi khi" của các truy vấn báo cáo như Tôi đã gợi ý ở trên), sau đó bạn phải sử dụng một chức năng thoát thích hợp. Đừng tự viết nó. Ví dụ postgres cung cấp hàm quote_literal (). Vì vậy, bạn sẽ chạy:
sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);
Theo cách này, nếu in_name là thứ gì đó lệch lạc như '[snip] hoặc 1 = 1' (phần "hoặc 1 = 1" có nghĩa là chọn tất cả các hàng, cho phép người dùng xem mức lương mà anh ta không nên!), Sau đó quote_literal sẽ lưu mông của bạn bằng cách tạo chuỗi kết quả:
SELECT salary FROM employees WHERE name = '[snip] or 1=1'
Sẽ không có kết quả nào được tìm thấy (trừ khi bạn có một số nhân viên có tên thực sự kỳ lạ.)
Đó là ý chính của nó! Bây giờ hãy để tôi chỉ cho bạn một liên kết đến một bài viết cổ điển của giáo sư Oracle Tom Kyte về chủ đề SQL Injection, để lái xe về nhà: Linky