2009-12-07 31 views
9
public static bool TruncateTable(string dbAlias, string tableName) 
{ 
    string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName); 
    return ExecuteNonQuery(dbAlias, sqlStatement) > 0; 
}
+2

Ai được phép gọi TruncateTable? – FrustratedWithFormsDesigner

+1

Không hề. Bạn cần sử dụng các truy vấn được tham số hóa để chắc chắn. http://www.c-sharpcorner.com/UploadFile/puranindia/ParameterizedQuerySQLInjectionAttacks08102009011903AM/ParameterizedQuerySQLInjectionAttacks.aspx –

+1

Tôi sẽ không nói chung cho phép giao diện người dùng gọi đến bảng cắt ngắn! Nếu bạn cần làm điều này, bạn có thể có một lỗ hổng thiết kế nghiêm trọng. – HLGEM

Trả lời

22

Đề xuất phổ biến nhất để chống lại SQL injection là sử dụng tham số truy vấn SQL (một số người trong chủ đề này đã đề xuất nó).

Đây là câu trả lời sai trong trường hợp này. Bạn không thể sử dụng tham số truy vấn SQL cho tên bảng trong câu lệnh DDL.

Tham số truy vấn SQL chỉ có thể được sử dụng thay cho giá trị bằng chữ trong biểu thức SQL. Đây là tiêu chuẩn trong mọi triển khai SQL.

Đề xuất của tôi để bảo vệ chống lại SQL injection khi bạn có tên bảng là xác thực chuỗi đầu vào dựa vào danh sách các tên bảng đã biết.

Bạn có thể nhận được một danh sách các tên bảng hiệu lực kể từ INFORMATION_SCHEMA:

SELECT table_name 
FROM INFORMATION_SCHEMA.Tables 
WHERE table_type = 'BASE TABLE' 
    AND table_name = @tableName 

Bây giờ bạn có thể vượt qua biến đầu vào của bạn để truy vấn này như một tham số SQL. Nếu truy vấn trả về không có hàng, bạn biết rằng đầu vào không hợp lệ để sử dụng làm bảng. Nếu truy vấn trả về một hàng, truy vấn đó phù hợp, vì vậy bạn có nhiều bảo đảm hơn, bạn có thể sử dụng nó một cách an toàn.

Bạn cũng có thể xác thực tên bảng dựa vào danh sách các bảng cụ thể mà bạn xác định là ứng dụng của bạn sẽ bị cắt bớt, như @John Buchanan suggests.

Ngay cả sau khi xác thực rằng tableName tồn tại dưới dạng tên bảng trong RDBMS của bạn, tôi cũng sẽ gợi ý phân định tên bảng, chỉ trong trường hợp bạn sử dụng tên bảng có dấu cách hoặc ký tự đặc biệt. Trong Microsoft SQL Server, delimiters nhận dạng mặc định là dấu ngoặc vuông:

string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName); 

Bây giờ bạn chỉ có nguy cơ bị SQL injection nếu tableName phù hợp với một bảng thực, và bạn thực sự sử dụng dấu ngoặc vuông trong tên của bảng của bạn!

+2

Xác thực đối với các đầu vào có thể biết. +1 – Greg

+0

Tôi nghĩ rất nhiều người đã quên rằng bạn không thể sử dụng các truy vấn được tham số hóa với kiểu truy vấn này. Quan sát tốt. –

+1

OP cũng nên xem xét khả năng của hai hoặc nhiều bảng có cùng tên nhưng thuộc về các chủ sở hữu/lược đồ khác nhau. – MartW

1

Có một cái nhìn tại liên kết này

Does this code prevent SQL injection?

Tháo không mong muốn từ các chuỗi tableName.

Tôi không nghĩ bạn có thể sử dụng truy vấn param cho tên bảng.

1

Sử dụng truy vấn được tham số hóa.

+3

Từ tên bảng? Bạn có một số liên kết để hỗ trợ điều này? –

+1

Câu trả lời kỳ lạ nhưng đúng. Một ví dụ nhỏ dựa trên mã OP sẽ tốt hơn. – AnthonyWJones

+0

Đúng, nhưng mọi người thực sự nên hiểu những nguy hiểm của việc cho phép bất kỳ chuỗi nào được chuyển vào truy vấn mà không sử dụng truy vấn được tham số hóa. Tôi không có thời gian để viết một ví dụ về mã, nhưng anh ta nên biết về chúng. –

2

Sử dụng quy trình được lưu trữ. Bất kỳ thư viện db phong nha (MS Enterprise Library là những gì tôi sử dụng) sẽ xử lý các thông số chuỗi thoát đúng cách.

Ngoài ra, lại: truy vấn được tham số hóa: Tôi không muốn triển khai lại ứng dụng của mình để khắc phục vấn đề về db. Lưu trữ các truy vấn dưới dạng chuỗi chữ trong nguồn của bạn làm tăng độ phức tạp của bảo trì.

+0

Nếu bạn không muốn triển khai lại, hãy làm điều đó một cách chính xác ngay từ đầu và kiểm tra nó. –

+4

Tại sao tôi không nghĩ về điều đó. Trong khi tôi đang ở đó, tôi sẽ chỉ dừng lại trong tất cả những lỗi ngu ngốc mà tôi đã mã hóa tất cả những năm này. Ngoài ra, thiên tài, * deploy * có thể có nghĩa là rất nhiều thứ - như đi từ hộp địa phương đến máy chủ dev. Gián đoạn các nhà phát triển khác bằng cách xây dựng lại/redploy để dev có thể là một sự gián đoạn khá lớn. –

+1

Nó cũng có thể gây rối để triển khai một phiên bản mới của một thủ tục lưu sẵn. –

-2

Bạn có thể sử dụng SQLParameter để chuyển giá trị tableName. Theo như tôi biết và thử nghiệm, SQLParameter sẽ chăm sóc tất cả các kiểm tra tham số và do đó vô hiệu hóa khả năng tiêm.

-4

Nếu bạn không thể sử dụng truy vấn được tham số hóa (và bạn nên) ... thay thế đơn giản tất cả các phiên bản 'bằng' 'sẽ hoạt động.

string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''")); 
+1

khó, điều gì về '-' – CaffGeek

+0

bạn nói đúng. thực sự có một số thứ cần được thay thế (ví dụ: '; -,/* */xp_, v.v ...) và do đó đề xuất của tôi sử dụng truy vấn được tham số hóa (hoặc bất kỳ tùy chọn hợp lệ nào khác, ví dụ như proc được lưu trữ, ORM, v.v ...). vẫn còn, cùng với việc hạn chế chiều dài của chuỗi "tableName" ... giải pháp này có thể sẽ hoạt động 100% thời gian. – wgpubs

6

Theo tôi biết, bạn không thể sử dụng truy vấn tham số để thực hiện lệnh DDL/chỉ định tên bảng, ít nhất không có trong Oracle hoặc Sql Server. Những gì tôi sẽ làm, nếu tôi đã có một chức năng TruncateTable điên, mà phải được an toàn từ tiêm sql sẽ được thực hiện một thủ tục lưu trữ kiểm tra rằng đầu vào là một bảng đó là an toàn để cắt ngắn.


-- Sql Server specific! 
CREATE TABLE TruncableTables (TableName varchar(50)) 
Insert into TruncableTables values ('MyTable') 

go 

CREATE PROCEDURE MyTrunc @tableName varchar(50) 
AS 
BEGIN 

declare @IsValidTable int 
declare @SqlString nvarchar(50) 
select @IsValidTable = Count(*) from TruncableTables where TableName = @tableName 

if @IsValidTable > 0 
begin 
select @SqlString = 'truncate table ' + @tableName 
EXECUTE sp_executesql @SqlString 
end 
END 
1

Có một số bài đăng khác sẽ trợ giúp với SQL injection Nếu bạn đang cấp cho người dùng db + chủ sở hữu hoặc vai trò db_ddladmin để họ có thể cắt bớt các bảng thì đơn giản là tránh các cuộc tấn công SQL injection chuẩn là không đủ. Một hacker có thể gửi các tên bảng khác có thể hợp lệ, nhưng bạn không muốn bị cắt ngắn.

Nếu bạn đang cấp quyền ALTER TABLE cho người dùng trên các bảng cụ thể mà bạn sẽ cho phép cắt bớt thì bạn có hình dạng tốt hơn một chút, nhưng vẫn nhiều hơn tôi muốn cho phép trong môi trường bình thường.

Thường thì TABLE TRUNCATE không được sử dụng trong việc sử dụng ứng dụng thông thường hàng ngày. Nó được sử dụng cho các kịch bản ETL hoặc trong quá trình bảo trì cơ sở dữ liệu. Tình huống duy nhất mà tôi có thể tưởng tượng nó sẽ được sử dụng trong ứng dụng mặt trước là nếu bạn cho phép người dùng tải một bảng cụ thể cho người dùng đó cho mục đích tải, nhưng thậm chí sau đó tôi có thể sử dụng một giải pháp khác.

Tất nhiên, không biết các chi tiết cụ thể về lý do bạn sử dụng nó, tôi không thể nói rằng bạn nên thiết kế lại, nhưng nếu tôi có yêu cầu làm DBA, tôi sẽ hỏi nhà phát triển các câu hỏi.

3

Nếu bạn cho phép người dùng xác định đầu vào để leo vào hàm này thông qua biến tablename, tôi không nghĩ rằng SQL Injection là vấn đề duy nhất của bạn.

Tùy chọn tốt hơn là chạy lệnh này thông qua kết nối an toàn của riêng nó và không cấp quyền SELECT. Tất cả TRUNCATE cần chạy là quyền ALTER TABLE. Nếu bạn đang ở trên SQL 2005 trở lên, bạn cũng có thể thử sử dụng một thủ tục được lưu trữ với EXECUTE AS bên trong.

0

Trong ví dụ cụ thể này, bạn cần bảo vệ khỏi việc tiêm SQL chỉ khi tên bảng đến từ nguồn bên ngoài.

Tại sao bạn lại cho phép điều này xảy ra? Nếu bạn cho phép một số thực thể bên ngoài (người dùng cuối, hệ thống khác, cái gì?) để đặt tên cho bảng bị xóa, tại sao bạn không cấp cho họ quyền quản trị.

Nếu bạn đang tạo và xóa bảng để cung cấp một số chức năng cho người dùng cuối, không cho phép họ cung cấp tên cho các đối tượng cơ sở dữ liệu trực tiếp. Ngoài việc chèn SQL, bạn sẽ gặp sự cố với các xung đột tên… Thay vào đó, hãy tự tạo tên bảng thực (ví dụ: DYNTABLE_00001, DYNTABLE_00002, ...) và giữ bảng kết nối chúng với tên do người dùng cung cấp.


Một số lưu ý vào việc tạo SQL năng động cho các hoạt động DDL:

  • Trong hầu hết các RDBMS-s bạn sẽ phải sử dụng SQL động và chèn tên bảng dưới dạng văn bản. Hãy cẩn thận hơn.

  • Sử dụng số nhận dạng được trích dẫn ([] trong MS SQL Server, "" trong tất cả RDBMS tuân thủ ANSI). Điều này sẽ giúp tránh các lỗi do tên không hợp lệ dễ dàng hơn.

  • Làm điều đó trong các thủ tục được lưu trữ và kiểm tra xem tất cả các đối tượng được tham chiếu có hợp lệ hay không.

  • Không làm bất cứ điều gì không thể đảo ngược. Ví dụ. không tự động thả bảng. Bạn có thể gắn cờ chúng để được thả và gửi e-mail cho DBA của bạn. Cô ấy sẽ thả chúng sau bản sao lưu.

  • Tránh nếu bạn có thể. Nếu bạn không thể, hãy làm những gì bạn có thể để giảm thiểu quyền đối với các bảng (không động) khác mà người dùng thông thường sẽ có.

3
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS 
    stmt VARCHAR2(100); 
BEGIN 
    stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name); 
    dbms_output.put_line('<'||stmt||'>'); 
    EXECUTE IMMEDIATE stmt; 
END; 
Các vấn đề liên quan