2011-05-14 33 views
25

Tôi cần bảo vệ ứng dụng khỏi việc tiêm SQL. Ứng dụng đang kết nối với Oracle, sử dụng ADO và tìm kiếm tên người dùng và mật khẩu để thực hiện xác thực.Delphi - ngăn chặn việc tiêm SQL

Từ những gì tôi đã đọc cho đến bây giờ, cách tiếp cận tốt nhất là sử dụng các tham số, không gán toàn bộ SQL làm chuỗi. Một cái gì đó như thế này:

query.SQL.Text := 'select * from table_name where name=:Name and id=:ID'; 
query.Prepare; 
query.ParamByName('Name').AsString := name; 
query.ParamByName('ID').AsInteger := id; 
query.Open; 

Ngoài ra, tôi đang suy nghĩ để xác minh đầu vào từ người dùng và xóa các từ khóa SQL như chữ cái và số ASCII bình thường sẽ bị xóa.

Điều này sẽ đảm bảo cho tôi mức độ bảo mật tối thiểu?

Tôi không muốn sử dụng bất kỳ thành phần nào khác so với tiêu chuẩn Delphi 7 và Jedi.

Trả lời

40

Safe

query.SQL.Text := 'select * from table_name where name=:Name'; 

Mã này là an toàn vì bạn đang sử dụng các thông số.
Các tham số luôn an toàn với SQL injection.

không an toàn

var Username: string; 
... 
query.SQL.Text := 'select * from table_name where name='+ UserName; 

là không an toàn vì Tên truy cập có thể là name; Drop table_name; Hệ quả là các truy vấn sau đây được thực thi.

select * from table_name where name=name; Drop table_name; 

Cũng không an toàn

var Username: string; 
... 
query.SQL.Text := 'select * from table_name where name='''+ UserName+''''; 

Bởi vì nó nếu username là ' or (1=1); Drop Table_name; -- Nó sẽ dẫn đến việc truy vấn sau đây:

select * from table_name where name='' or (1=1); Drop Table_name; -- ' 

Nhưng mã này là an toàn

var id: integer; 
... 
query.SQL.Text := 'select * from table_name where id='+IntToStr(id); 

IntToStr() sẽ chỉ chấp nhận số nguyên nên không có mã SQL có thể được tiêm vào chuỗi truy vấn theo cách này, chỉ số (đó là chính xác những gì bạn muốn và do đó cho phép)

Nhưng tôi muốn làm những thứ không thể thực hiện được với thông số

Chỉ có thể sử dụng thông số cho giá trị. Họ không thể thay thế tên trường hoặc tên bảng. Vì vậy, nếu bạn muốn thực hiện truy vấn này

query:= 'SELECT * FROM :dynamic_table '; {doesn't work} 
query:= 'SELECT * FROM '+tableName;  {works, but is unsafe} 

Truy vấn đầu tiên không thành công vì bạn không thể sử dụng tham số cho tên bảng hoặc trường.
Truy vấn thứ hai là không an toàn nhưng là cách duy nhất điều này có thể được thực hiện.
Làm thế nào để bạn được an toàn?

Bạn phải kiểm tra chuỗi tablename đối với danh sách các tên được phê duyệt.

Const 
    ApprovedTables: array[0..1] of string = ('table1','table2'); 

procedure DoQuery(tablename: string); 
var 
    i: integer; 
    Approved: boolean; 
    query: string; 
begin 
    Approved:= false; 
    for i:= lo(ApprovedTables) to hi(ApprovedTables) do begin 
    Approved:= Approved or (lowercase(tablename) = ApprovedTables[i]); 
    end; {for i} 
    if not Approved then exit; 
    query:= 'SELECT * FROM '+tablename; 
    ... 

Đó là cách duy nhất để làm điều này, mà tôi biết.

BTW mã ban đầu của bạn có một lỗi:

query.SQL.Text := 'select * from table_name where name=:Name where id=:ID'; 

Nên

query.SQL.Text := 'select * from table_name where name=:Name and id=:ID'; 

Bạn không thể có hai where 's trong một (sub) truy vấn

+0

cảm ơn Johan. Tôi đã sửa câu hỏi + 1 – RBA

+0

+1 để bao gồm nhiều trường hợp –

+0

Nhưng bạn vẫn có thể tiêm tham số SQL bằng 'name; Thả table_name; 'nếu nó được người dùng nhập vào trong loại hộp nhập đó –

6

This will assure me a minimum of security level?

Có truy vấn được yêu cầu sẽ bảo vệ bạn khỏi việc tiêm SQL dễ kiểm tra. Chỉ cần nhập một số chuỗi nguy hiểm vào biến số name và xem điều gì sẽ xảy ra. Thông thường bạn sẽ nhận được 0 hàng trả về và không phải là lỗi.

12

Nếu bạn cho phép người dùng tác động chỉ giá trị của thông số sẽ bị ràng buộc vào văn bản lệnh sql với trình giữ chỗ, thì bạn không thực sự cần phải kiểm tra những gì người dùng nhập: cách đơn giản nhất để tránh SQL , như bạn đề cập, là tránh SQL ghép, và sử dụng các biến bị ràng buộc (hoặc gọi thủ tục) thực hiện điều này (nó cũng có lợi thế - số dặm/sự liên quan phụ thuộc vào cơ sở dữ liệu - cho phép động cơ sử dụng lại các kế hoạch truy vấn).

Nếu bạn đang sử dụng Oracle, bạn cần có lý do thực sự tốt cho không phải sử dụng các biến bị ràng buộc: Tom Kyte có rất nhiều thông tin tốt về điều này trên trang web của mình http://asktom.oracle.com. Chỉ cần nhập "biến bị ràng buộc" vào hộp tìm kiếm.

+1

1 - các cách tốt nhất để tránh SQL injection không phải là để gửi SQL qua dây. – Vector

Các vấn đề liên quan