Các thủ tục lưu trữ có ngăn chặn SQL tiêm không?


83

Có đúng là các thủ tục được lưu trữ ngăn chặn các cuộc tấn công SQL SQL chống lại cơ sở dữ liệu PostgreSQL không? Tôi đã làm một nghiên cứu nhỏ và phát hiện ra rằng SQL Server, Oracle và MySQL không an toàn trước việc tiêm SQL ngay cả khi chúng tôi chỉ sử dụng các thủ tục được lưu trữ. Tuy nhiên, vấn đề này không tồn tại trong PostgreSQL.

Liệu việc thực hiện thủ tục được lưu trữ trong lõi PostgreSQL có ngăn chặn các cuộc tấn công SQL SQL hay không? Hoặc PostgreSQL cũng dễ bị tiêm SQL ngay cả khi chúng tôi chỉ sử dụng các thủ tục được lưu trữ? Nếu vậy, xin vui lòng cho tôi xem một ví dụ (ví dụ: sách, trang web, giấy, v.v.).


4
Điều kỳ lạ, các câu trả lời hàng đầu ở đây chủ yếu là xử lý OT với SQL Server trong khi câu hỏi là về Postgres . Đây là câu trả lời liên quan cho Postgres: dba.stackexchange.com/questions/49699/ mẹo . Có một vài người khác, hãy thử tìm kiếm: dba.stackexchange.com/ Kẻ
Erwin Brandstetter

@ErwinBrandstetter câu hỏi ban đầu không được gắn thẻ (bởi OP) với các postgres và đã - và vẫn - đề cập đến một số DBMS khác. Tôi đoán đó là lý do của các câu trả lời khác nhau tập trung vào các DBMS khác. Tôi đề nghị bạn thêm một tập trung vào Postgres.
ypercubeᵀᴹ

@ ypercubeᵀᴹ: Tôi sẽ thêm câu trả lời ở đây khi tôi tìm thấy thời gian. Trong thời gian chờ đợi, tôi đã cập nhật dba.stackexchange.com/questions/49699/ vào để rõ ràng và toàn diện hơn.
Erwin Brandstetter

Câu trả lời:


71

Không, các thủ tục được lưu trữ không ngăn chặn SQL tiêm. Đây là một ví dụ thực tế (từ một ứng dụng nội bộ mà ai đó đã tạo ra nơi tôi làm việc) của một thủ tục được lưu trữ không may cho phép tiêm SQL:

Mã máy chủ sql này:

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO

gần tương đương với postgres:

CREATE or replace FUNCTION public.sp_colunmName2 (
    columnName  varchar(30),
    type varchar(30), 
    searchText  varchar(30) ) RETURNS SETOF stations LANGUAGE plpgsql            
AS
$$
DECLARE SQLStatement VARCHAR(4000);
BEGIN
    SQLStatement = 'select * from Stations where ' 
            || columnName || ' ' || type || ' ' || ''''|| searchText || '''';
    RETURN QUERY EXECUTE  SQLStatement;
END
$$;

Ý tưởng của nhà phát triển là tạo ra một quy trình tìm kiếm linh hoạt, nhưng kết quả là mệnh đề WHERE có thể chứa bất cứ thứ gì người dùng muốn, cho phép truy cập từ các Bảng Bobby nhỏ .

Cho dù bạn sử dụng câu lệnh SQL hay thủ tục lưu trữ đều không thành vấn đề. Vấn đề là liệu SQL của bạn có sử dụng các tham số hoặc chuỗi được nối hay không. Các tham số ngăn SQL tiêm; chuỗi kết nối cho phép tiêm SQL.


46

Các cuộc tấn công SQL-Injection là những cuộc tấn công mà các đầu vào không tin cậy được nối trực tiếp vào các truy vấn, cho phép người dùng thực thi hiệu quả mã tùy ý, như được minh họa trong truyện tranh XKCD kinh điển này.

Vì vậy, chúng ta có được tình huống:

userInput = getFromHTML # "Robert ') Thả học sinh bảng; -"

Truy vấn = "Chọn * từ sinh viên nơi studentName =" + userInput

Các thủ tục được lưu trữ, nói chung, phòng thủ tốt chống lại các cuộc tấn công tiêm nhiễm SQL vì các tham số đến không bao giờ được phân tích cú pháp.

Trong một thủ tục được lưu trữ, trong hầu hết các DB (và chương trình, đừng quên rằng các truy vấn được biên dịch trước được tính là các thủ tục được lưu trữ) trông giống như sau:

 

tạo foo procdure lưu trữ (
chọn * từ sinh viên nơi studentName =: 1
);

Sau đó, khi chương trình mong muốn truy cập, nó gọi foo(userInput)và vui vẻ lấy kết quả.

Một thủ tục được lưu trữ không phải là một biện pháp bảo vệ kỳ diệu chống lại SQL-Injection, vì mọi người hoàn toàn có thể viết các thủ tục được lưu trữ xấu . Tuy nhiên, các truy vấn được biên dịch trước, có thể được lưu trữ trong cơ sở dữ liệu hoặc trong chương trình, sẽ khó mở lỗ hổng bảo mật hơn nhiều nếu bạn hiểu cách SQL-Injection hoạt động.

Bạn có thể đọc thêm về SQL-Injection:


29

Vâng, ở một mức độ nào đó.
Thủ tục lưu trữ một mình sẽ không ngăn chặn SQL Injection.

Trước tiên, hãy để tôi trích dẫn về SQL Injection từ OWASP

Một cuộc tấn công tiêm SQL bao gồm chèn hoặc "tiêm" truy vấn SQL thông qua dữ liệu đầu vào từ máy khách đến ứng dụng. Khai thác SQL SQL thành công có thể đọc dữ liệu nhạy cảm từ cơ sở dữ liệu, sửa đổi dữ liệu cơ sở dữ liệu (Chèn / Cập nhật / Xóa), thực hiện các thao tác quản trị trên cơ sở dữ liệu (như tắt DBMS), khôi phục nội dung của tệp đã cho trên tệp DBMS hệ thống và trong một số trường hợp phát lệnh cho hệ điều hành. Các cuộc tấn công tiêm nhiễm SQL là một loại tấn công tiêm chích, trong đó các lệnh SQL được đưa vào đầu vào mặt phẳng dữ liệu để thực hiện việc thực thi các lệnh SQL được xác định trước.

Bạn phải vệ sinh đầu vào của người dùng và không nối các câu lệnh SQL, ngay cả khi bạn đang sử dụng thủ tục được lưu trữ.

Jeff Attwood đã giải thích hậu quả của việc ghép sql trong " Cho tôi tham số SQL hoặc cho tôi cái chết "

Sau đây là phim hoạt hình thú vị xuất hiện trong đầu tôi mỗi khi tôi nghe SQL Injection văn bản thay thế Tôi nghĩ bạn đã hiểu :-)

Hãy xem SQL Cheat Sheet Cheat Sheet , các phương pháp phòng ngừa được giải thích gọn gàng ...


12

Nối chuỗi là nguyên nhân của SQL Injection. Điều này được tránh sử dụng tham số.

Các thủ tục được lưu trữ thêm một lớp bảo mật bổ sung bằng cách thực thi cú pháp không hợp lệ khi bạn ghép nối, nhưng không "an toàn" hơn nếu bạn sử dụng, giả sử, SQL động trong chúng.

Vì vậy, mã của bạn ở trên là do nối các chuỗi này

  • exec sp_GetUser '
  • x' AND 1=(SELECT COUNT(*) FROM Client); --
  • ' , '
  • monkey
  • '

Điều này cho cú pháp không hợp lệ, may mắn thay

Tham số hóa nó sẽ cung cấp cho

exec sp_GetUser 'x'' AND 1=(SELECT COUNT(*) FROM Client); --' , 'monkey'

Điều này có nghĩa là

  • @UserName = = x' AND 1=(SELECT COUNT(*) FROM Client); --
  • @Password = = monkey

Bây giờ, trong đoạn mã trên, bạn sẽ không nhận được hàng nào vì tôi cho rằng bạn không có người dùng x' AND 1=(SELECT COUNT(*) FROM Client); --

Nếu Proc được lưu trữ trông như thế này (sử dụng SQL động được nối ), thì cuộc gọi Proc được lưu trữ được tham số hóa của bạn vẫn sẽ cho phép SQL Injection

...
SET @sql = 'SELECT userName from users where userName = ''' + 
               @UserName + 
               ''' and userPass = ''' +
               @Password +
               ''''
EXEC (@sql)
....

Vì vậy, như đã chứng minh, nối chuỗi là kẻ thù chính của SQL SQL

Các thủ tục được lưu trữ để thêm đóng gói, xử lý giao dịch, giảm quyền, v.v., nhưng chúng vẫn có thể bị lạm dụng để tiêm SQL.

Bạn có thể xem trên Stack Overflow để biết thêm về tham số hóa


10

"Tấn công SQL injection xảy ra khi người dùng nhập vào là không đúng mã hóa. Thông thường, người dùng nhập vào được một số dữ liệu người dùng gửi với truy vấn của mình, giá trị tức là trong $_GET, $_POST, $_COOKIE, $_REQUEST, hoặc $_SERVERmảng. Tuy nhiên, người dùng nhập vào cũng có thể xuất phát từ nhiều loại khác các nguồn, như ổ cắm, trang web từ xa, tệp, v.v. Do đó, bạn thực sự nên coi mọi thứ trừ hằng số (như 'foobar') là đầu vào của người dùng . "

Gần đây tôi đã nghiên cứu kỹ về chủ đề này và muốn chia sẻ với những người khác tài liệu khá thú vị, do đó, làm cho bài đăng này đầy đủ hơn và mang tính hướng dẫn cho mọi người.



Từ YouTube


Từ Wikipedia


Từ OWASP


Từ hướng dẫn sử dụng PHP


Từ Microsoft và Oracle


Tràn ngăn xếp


Máy quét SQL SQL


2

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


Đừng quên đề cập quote_ident()- nhưng nói chung cách dễ nhất để viết SQL động chống tiêm là sử dụng format()và sử dụng trình giữ chỗ %Icho mã định danh và %Lcho chữ. Bằng cách đó, SQL dễ đọc hơn nhiều so với phiên bản tương đương sử dụng ||và các quote_....()hàm
a_horse_with_no_name
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.