Có an toàn không khi không tham số hóa một truy vấn SQL khi tham số không phải là một chuỗi?


113

Về SQL injection , tôi hoàn toàn hiểu sự cần thiết phải tham số hóa một stringtham số; đó là một trong những thủ thuật lâu đời nhất trong cuốn sách. Nhưng khi nào thì có thể biện minh cho việc không tham số hóa an SqlCommand? Có bất kỳ kiểu dữ liệu nào được coi là "an toàn" để không tham số hóa không?

Ví dụ: Tôi không tự cho mình là ở gần một chuyên gia về SQL, nhưng tôi không thể nghĩ ra bất kỳ trường hợp nào có thể dễ bị tấn công bởi SQL injection để chấp nhận một boolhoặc một intvà chỉ nối nó ngay vào truy vấn.

Giả định của tôi có đúng không hay điều đó có khả năng để lại lỗ hổng bảo mật lớn trong chương trình của tôi?

Để làm rõ, câu hỏi này được gắn thẻ vốn là một ngôn ngữ được đánh máy mạnh; khi tôi nói "tham số", hãy nghĩ như thế nào public int Query(int id) .


14
Bạn sẽ không nhận được lợi ích của các kế hoạch truy vấn đã lưu trong bộ nhớ cache nếu không sử dụng các tham số, nó sẽ cần phải tạo một kế hoạch truy vấn riêng cho mọi kết hợp đầu vào mới mà bạn cung cấp.
Scott Chamberlain

5
@MatthewWhited Làm thế nào bạn biết nó mất ít thời gian hơn? Tình trạng này xảy ra khắp nơi trong các dự án nhất định từ một nhà phát triển hiện tại và nhà phát triển trước đó. Nếu nó thực sự cải thiện bảo mật, vui lòng đăng câu trả lời. Để làm rõ, tôi đồng ý rằng tốt hơn là nên tham số hóa, rõ ràng. Nhưng đó không thực sự là câu hỏi của tôi.
johnnyRose

7
Các truy vấn được tham số hóa chủ yếu được sử dụng cho hiệu suất và tối ưu hóa. Ngăn chặn SQL injection là một tác dụng phụ.
Salman A

13
Tôi nghĩ OP đã hỏi một câu hỏi hợp lệ. Anh ta đang cố gắng đánh giá chi phí / lợi ích của việc khắc phục rủi ro tiềm ẩn. phương trình đó thay đổi theo tiềm năng của rủi ro đó. nếu không có rủi ro, tôi cũng sẽ không làm điều đó. Anh ấy yêu cầu một câu hỏi kỹ thuật về tiềm năng, không phải để đánh giá chủ quan về việc bạn có nghĩ rằng nó xứng đáng với thời gian của anh ấy hay không. OP là người duy nhất có thể thực hiện cuộc gọi đó.
Sir Swears-a-lot, 19/09/15

10
Để giải thích bản thân: Tôi là một dba. Tôi đánh giá cao và tôn trọng phương pháp hay nhất, và trong một thế giới hoàn hảo, tất cả mã sẽ hoàn hảo. Thật đáng buồn trong thế giới mà tôi đang làm việc, tôi có nhiều vấn đề cần giải quyết hơn là thời gian để giải quyết chúng. Điều đó có nghĩa là phải ưu tiên. IMO Viết lại mã đã hoạt động, an toàn và hoạt động ở mức chấp nhận được nghe có vẻ xa xỉ. (Đó là tôi không thể đủ khả năng)
Sir thề-a-lot

Câu trả lời:


101

Tôi nghĩ rằng nó an toàn ... về mặt kỹ thuật , nhưng đó là một thói quen khủng khiếp. Bạn có thực sự muốn viết các truy vấn như thế này không?

var sqlCommand = new SqlCommand("SELECT * FROM People WHERE IsAlive = " + isAlive + 
" AND FirstName = @firstName");

sqlCommand.Parameters.AddWithValue("firstName", "Rob");

Nó cũng khiến bạn dễ bị tổn thương trong trường hợp kiểu thay đổi từ số nguyên thành chuỗi (Hãy nghĩ đến số nhân viên, mặc dù tên của nó - có thể chứa các chữ cái).

Vì vậy, chúng tôi đã thay đổi loại EmployeeNumber từ intthành string, nhưng quên cập nhật các truy vấn sql của chúng tôi. Giáo sư.


24
Chúng tôi có thể ngừng sử dụng AddWithValue đã? blogs.msmvps.com/jcoehoorn/blog/2014/05/12/...
RemarkLima

5
@RemarkLima Giải pháp là gì khi bạn đang tạo động mã ánh xạ các giá trị cho các tham số? Bài đăng trên blog không giải quyết được tình huống đó. Đúng, đó là một dòng duy nhất để đặt kiểu SQL khi nó được biết đến , nhưng khi không, thì bạn gặp sự cố (hoặc bạn phải dùng đến chú thích các mô hình với thông tin đó).
casperMột

1
Sau đó, bạn bị mắc kẹt AddWithValuetrừ khi bạn có ánh xạ các loại cơ sở dữ liệu như một phần của cấu trúc động của câu lệnh. Tôi giả sử rằng bạn có một danh sách các cột mục tiêu và là một phần của từ điển, bạn có thể có các loại nếu bạn muốn. Nếu không, chỉ cần đạt được hiệu suất. Cuối cùng, đó chỉ là thông tin tốt để biết tôi nghĩ.
RemarkLima

8
@RemarkLima Vấn đề là "Chúng ta có thể ngừng sử dụng AddWithValuerồi không?" thực sự nên là "nếu bạn biết loại, thì bạn nên hạn chế sử dụng AddWithValue.
casperOne

2
Này, đừng bắn người đưa tin, tôi không viết nó ;-) nhưng vấn đề vẫn còn, và nếu được tích hợp vào thiết kế của bạn ngay từ đầu, không có lý do gì bạn không biết loại. Thực hành tốt nhất và tất cả jazz đó :-)
RemarkLima

65

Khi sử dụng một nền tảng mạnh mẽ, đánh máy trên một máy tính bạn kiểm soát (như một máy chủ web), bạn có thể ngăn chặn tiêm mã cho các truy vấn với chỉ bool, DateTimehoặc int(và số khác) giá trị. Điều đáng lo ngại là các vấn đề về hiệu suất gây ra bởi việc buộc máy chủ sql phải biên dịch lại mọi truy vấn và bằng cách ngăn nó nhận được số liệu thống kê tốt về những truy vấn được chạy với tần suất nào (điều này ảnh hưởng đến việc quản lý bộ nhớ cache).

Nhưng phần "trên máy tính mà bạn điều khiển" là quan trọng, vì nếu không thì người dùng có thể thay đổi hành vi được hệ thống sử dụng để tạo chuỗi từ các giá trị đó để bao gồm văn bản tùy ý.

Tôi cũng thích suy nghĩ dài hạn. Điều gì sẽ xảy ra khi cơ sở mã được đánh máy mạnh mẽ ngày nay được chuyển qua bản dịch tự động sang ngôn ngữ động mới nổi và bạn đột nhiên mất kiểm tra kiểu, nhưng chưa có tất cả các kiểm tra đơn vị phù hợp cho mã động ?

Thực sự, không có lý do chính đáng nào để không sử dụng các tham số truy vấn cho các giá trị này. Đó là cách đúng đắn để thực hiện điều này. Hãy tiếp tục và nhập các giá trị mã cứng vào chuỗi sql khi chúng thực sự là hằng số, nhưng nếu không, tại sao không chỉ sử dụng một tham số? Nó không giống như nó khó.

Cuối cùng, tôi sẽ không gọi đây là một lỗi , nhưng tôi sẽ gọi nó là một mùi : một thứ gì đó chỉ giống như một lỗi của chính nó, nhưng là một dấu hiệu mạnh mẽ rằng các lỗi đang ở gần hoặc cuối cùng sẽ là. Mã tốt sẽ tránh để lại mùi và bất kỳ công cụ phân tích tĩnh nào tốt sẽ gắn cờ điều này.

Tôi sẽ nói thêm rằng đây không phải là loại tranh luận mà bạn có thể thắng ngay lập tức. Nghe có vẻ như một tình huống mà "đúng" là không còn đủ và việc đồng nghiệp của bạn cố gắng khắc phục vấn đề này không có khả năng thúc đẩy động lực nhóm tốt; cuối cùng nó có thể làm tổn thương nhiều hơn nó giúp. Một cách tiếp cận tốt hơn trong trường hợp này có thể là thúc đẩy việc sử dụng công cụ phân tích tĩnh. Điều đó sẽ mang lại tính hợp pháp và độ tin cậy cho những nỗ lực nhằm mục đích và quay lại và sửa mã hiện có.


1
Nó chắc chắn không phải là một thách thức để làm điều đó được tham số hóa. Câu hỏi của tôi nảy sinh vì một đồng nghiệp đã viết một loạt các truy vấn nối các giá trị số nguyên và tôi đang tự hỏi liệu có lãng phí thời gian của mình để xem qua và sửa tất cả chúng hay không.
johnnyRose

2
Tôi nghĩ câu hỏi "Nó có phải là một lỗi không" là câu hỏi của tôi.
johnnyRose

7
Đó là "mùi": một thứ gì đó tự nó không có lỗi, nhưng chỉ ra rằng có thể có lỗi ở gần đó. Mã tốt cố gắng loại bỏ mùi. Bất kỳ công cụ phân tích tĩnh nào tốt chắc chắn sẽ gắn cờ nó.
Joel Coehoorn

1
Tôi thích thuật ngữ "mùi". Thay vào đó, tôi đã sử dụng một cái gì đó như "ấu trùng", nơi nó chưa hoàn toàn là một lỗi, nhưng các bản cập nhật trong tương lai có thể bắt nó thành một con giòi sẽ ăn phần phụ trợ của bạn cho đến khi bạn nghiền nát nó hoặc hun trùng. Bạn chắc chắn không muốn khả năng xuất hiện mã hoại tử trong môi trường sản xuất và việc có một thứ gì đó không được phát triển với độ tinh xảo nhất định chắc chắn có thể gây ra hiện tượng đó, như trong trường hợp này.
CSS

1
Điều này chỉ là sai. Xem câu trả lời của tôi cho ví dụ về cách bạn vẫn có thể tạo SQL injection với DateTimehoặcint
Kaspars Ozols

53

Trong một số trường hợp, có thể thực hiện tấn công SQL injection với các biến không được tham số hóa (nối) khác với giá trị chuỗi - xem bài viết này của Jon: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables -căn hóa / .

Vấn đề là khi ToStringđược gọi, một số nhà cung cấp văn hóa tùy chỉnh có thể chuyển đổi một tham số không phải là chuỗi thành biểu diễn chuỗi của nó để đưa một số SQL vào truy vấn.


14
Tôi nghĩ rằng đây là bài đăng duy nhất trả lời câu hỏi, về cơ bản là "Làm thế nào có thể tiêm thuốc với ints?"
Arturo Torres Sánchez

3
Mặc dù nếu bạn đang ở trong một vị trí để tiêm mã tùy chỉnh, chẳng hạn như booby bị mắc kẹt CultureInfokhó biết tại sao bạn sẽ cần tiêm SQL.
Martin Smith

cộng với 1, câu trả lời duy nhất mà thực sự trả lời các câu hỏi
ken2k

@MartinSmith: xem câu trả lời của tôi cho thấy một cách khả thi để thay đổi CultureInfo từ bên ngoài.
user1027167

Nếu một người có thể viết mã như vậy trong ứng dụng, tại sao anh ta lại cần SQL Injection?
Reza Aghaei

51

Điều này không an toàn ngay cả đối với các loại không phải chuỗi. Luôn sử dụng các tham số. Giai đoạn = Stage.

Hãy xem xét ví dụ mã sau:

var utcNow = DateTime.UtcNow;
var sqlCommand = new SqlCommand("SELECT * FROM People WHERE created_on <= '" + utcNow + "'");

Thoạt nhìn, mã có vẻ an toàn, nhưng mọi thứ sẽ thay đổi nếu bạn thực hiện một số thay đổi trong Cài đặt khu vực của Windows và thêm nội dung ở định dạng ngày ngắn:

Ngày giờ tiêm

Bây giờ văn bản lệnh kết quả trông giống như sau:

SELECT * FROM People WHERE created_on <= '26.09.2015' OR '1'<>' 21:21:43'

Điều tương tự cũng có thể được thực hiện đối với intkiểu vì người dùng có thể xác định dấu phủ định tùy chỉnh có thể dễ dàng thay đổi thành SQL injection.

Người ta có thể tranh luận rằng nên sử dụng văn hóa bất biến thay vì văn hóa hiện tại, nhưng tôi đã thấy các đoạn nối chuỗi như thế này rất nhiều lần và khá dễ dàng bỏ sót khi nối các chuỗi với các đối tượng đang sử dụng +.


10
Ai có thể thay đổi cài đặt máy chủ? Nếu một người có thể làm điều đó trong máy chủ của bạn, anh ta không cần SQL Injection để phá hủy dữ liệu.
Reza Aghaei

5
Đây là câu trả lời tốt nhất, nó cho thấy một cách xác nhận mối quan tâm của OPs đây là một lỗi / lỗ hổng bảo mật. Ví dụ: hiệu suất và kiểm tra trong tương lai sang một bên lịch ngày nối trong SQL không chỉ là một mùi hoặc nợ công nghệ . @RezaAghaei câu hỏi chưa bao giờ đề cập đến Server-Side, nó có thể là một Ứng dụng Windows với SQLExpress - theo cách đó, đó không phải là tiêu chí cho câu hỏi. Bất kỳ ai cũng có thể nói nhưng ai có quyền truy cập vào cài đặt máy chủ để bác bỏ câu trả lời xuất sắc này, cũng như bất kỳ ai có thể nói gì về việc lưu trữ máy chủ được chia sẻ hoặc lỗi Y2K. Tôi đồng ý với bạn rằng máy chủ đang bị khóa - nó không phải là yêu cầu tiên quyết.
Jeremy Thompson

2
Bạn có thể cung cấp một ví dụ về những gì bạn đã nói về intloại này?
johnnyRose

1
Tôi biết đã được vài tuần kể từ khi bạn trả lời câu hỏi này, nhưng liệu bạn có thể chỉnh sửa bài đăng của mình và thêm một ví dụ về cách bạn có thể xác định dấu phủ định tùy chỉnh không?
johnnyRose

23

"CHỌN * TỪ Table1 WHERE Id =" + intVariable.ToString ()


Bảo mật
Nó được.
Những kẻ tấn công không thể đưa bất cứ thứ gì vào biến int đã nhập của bạn.

Hiệu suất
không ổn.

Tốt hơn là sử dụng các tham số, vì vậy truy vấn sẽ được biên dịch một lần và được lưu vào bộ nhớ cache để sử dụng tiếp theo. Lần tới, ngay cả với các giá trị tham số khác nhau, truy vấn được lưu vào bộ nhớ cache và không cần biên dịch trong máy chủ cơ sở dữ liệu.

Coding Style
Thực hành không tốt.

  • Các thông số dễ đọc hơn
  • Có thể nó khiến bạn quen với các truy vấn không có tham số, sau đó có thể bạn đã mắc lỗi một lần và sử dụng giá trị chuỗi theo cách này và sau đó bạn có thể nên tạm biệt dữ liệu của mình. Thói quen xấu!


"CHỌN * TỪ Sản phẩm WHERE Id =" + TextBox1.Text


Mặc dù nó không phải là câu hỏi của bạn, nhưng có thể hữu ích cho những người đọc trong tương lai:


Thảm họa an ninh !
Ngay cả khi Idtrường là số nguyên, truy vấn của bạn có thể bị SQL Injection. Giả sử bạn có một truy vấn trong ứng dụng của mình "SELECT * FROM Table1 WHERE Id=" + TextBox1.Text, Kẻ tấn công có thể chèn vào hộp văn bản 1; DELETE Table1và truy vấn sẽ là:

"SELECT * FROM Table1 WHERE Id=1; DELETE Table1"

Nếu bạn không muốn sử dụng truy vấn được tham số hóa ở đây, bạn nên sử dụng các giá trị đã nhập:

string.Format("SELECT * FROM Table1 WHERE Id={0}", int.Parse(TextBox1.Text))


Câu hỏi của bạn


Câu hỏi của tôi nảy sinh vì một đồng nghiệp đã viết một loạt các truy vấn nối các giá trị số nguyên và tôi đang tự hỏi liệu có lãng phí thời gian của mình để xem qua và sửa tất cả chúng hay không.

Tôi nghĩ rằng việc thay đổi những mã đó không lãng phí thời gian. Thật vậy, thay đổi được khuyến khích!

nếu đồng nghiệp của bạn sử dụng biến int, nó không có rủi ro bảo mật, Nhưng tôi nghĩ rằng việc thay đổi những mã đó không lãng phí thời gian và thực sự nên thay đổi những mã đó. Nó làm cho mã dễ đọc hơn, dễ bảo trì hơn và thực thi nhanh hơn.


Ngay cả tùy chọn đầu tiên cũng không hoàn toàn ổn về bảo mật. Hành vi của .ToString()được xác định bởi một mục cấu hình hệ điều hành dễ thay đổi để bao gồm văn bản tùy ý.
Joel Coehoorn

18

Thực ra có hai câu hỏi trong một. Và câu hỏi từ tiêu đề có rất ít liên quan đến mối quan tâm của OP trong các bình luận sau đó.

Mặc dù tôi nhận thấy rằng đối với OP thì vấn đề cụ thể của họ mới là vấn đề quan trọng, đối với độc giả đến từ Google, điều quan trọng là phải trả lời cho câu hỏi tổng quát hơn, có thể được diễn giải là "nối an toàn như các câu đã chuẩn bị sẵn nếu tôi chắc chắn rằng mọi chữ tôi đang nối có an toàn không? ". Vì vậy, tôi muốn tập trung vào phần sau này. Và câu trả lời là

Tất nhiên là không.

Lời giải thích không trực tiếp như hầu hết độc giả mong muốn, nhưng tôi sẽ cố gắng hết sức.

Tôi đã cân nhắc về vấn đề này trong một thời gian, dẫn đến bài viết (mặc dù dựa trên môi trường PHP), nơi tôi đã cố gắng tổng hợp mọi thứ. Tôi nhận ra rằng câu hỏi về việc bảo vệ khỏi SQL injection thường bị né tránh đối với một số chủ đề có liên quan nhưng hẹp hơn, như thoát chuỗi, ép kiểu, v.v. Mặc dù một số biện pháp có thể được coi là an toàn khi tự thực hiện, nhưng không có hệ thống, cũng như quy tắc đơn giản để tuân theo. Điều này làm cho nền đất rất trơn trượt, đặt quá nhiều vào sự chú ý và kinh nghiệm của nhà phát triển.

Câu hỏi về SQL injection không thể được đơn giản hóa thành một vấn đề cú pháp cụ thể nào đó. Nó rộng hơn các nhà phát triển trung bình thường nghĩ. Đó cũng là một câu hỏi về phương pháp luận . Nó không chỉ là "Chúng tôi phải áp dụng định dạng cụ thể nào", mà còn là " Nó phải được thực hiện như thế nào ".

(Từ quan điểm này, một bài báo của Jon Skeet được trích dẫn trong câu trả lời khác đang làm khá tệ hơn là tốt, vì nó lại phản bác một số trường hợp phức tạp, tập trung vào một vấn đề cú pháp cụ thể và không giải quyết được toàn bộ vấn đề.)

Khi bạn đang cố gắng giải quyết câu hỏi bảo vệ không phải toàn bộ mà là một loạt các vấn đề cú pháp khác nhau, bạn đang đối mặt với vô số vấn đề.

  • danh sách các lựa chọn định dạng có thể thực sự rất lớn. Có nghĩa là người ta có thể dễ dàng bỏ qua một số. Hoặc nhầm lẫn chúng (bằng cách sử dụng chuỗi thoát cho mã định danh chẳng hạn).
  • Kết hợp có nghĩa là tất cả các biện pháp bảo vệ phải được thực hiện bởi lập trình viên, không phải chương trình. Chỉ riêng vấn đề này đã dẫn đến một số hậu quả:
    • định dạng như vậy là thủ công. Thủ công có nghĩa là rất dễ xảy ra lỗi. Đơn giản là người ta có thể quên nộp đơn.
    • hơn nữa, có một sự cám dỗ để di chuyển các thủ tục định dạng vào một số chức năng tập trung, làm mọi thứ rối tung hơn nữa và làm hỏng dữ liệu không được đưa vào cơ sở dữ liệu.
  • khi có nhiều nhà phát triển tham gia, các vấn đề sẽ nhân lên với hệ số mười.
  • khi phép nối được sử dụng, người ta không thể chỉ ra một truy vấn tiềm ẩn nguy hiểm: tất cả chúng đều tiềm ẩn nguy hiểm!

Không giống như mớ hỗn độn đó, những tuyên bố chuẩn bị thực sự là Chén Thánh:

  • nó có thể được diễn đạt dưới dạng một quy tắc đơn giản dễ làm theo.
  • về cơ bản nó là biện pháp không thể lưu trữ, có nghĩa là nhà phát triển không thể can thiệp, và dù cố ý hay không cố ý, làm hỏng quá trình.
  • bảo vệ khỏi tiêm thực sự chỉ là một tác dụng phụ của các câu lệnh chuẩn bị, mục đích thực sự là tạo ra câu lệnh đúng cú pháp. Và một câu lệnh đúng về mặt cú pháp là bằng chứng tiêm 100%. Tuy nhiên, chúng tôi cần cú pháp của chúng tôi phải chính xác bất chấp khả năng tiêm bất kỳ.
  • nếu được sử dụng tất cả các cách xung quanh, nó bảo vệ ứng dụng bất kể kinh nghiệm của nhà phát triển. Nói rằng, có một thứ gọi là tiêm bậc hai . Và một ảo tưởng rất mạnh rằng "để bảo vệ, Thoát khỏi Tất cả Đầu vào do Người dùng Cung cấp ". Kết hợp với nhau, chúng sẽ dẫn đến sự tiêm nhiễm, nếu một nhà phát triển có quyền tự do quyết định, điều gì cần được bảo vệ và điều gì không.

(Suy nghĩ xa hơn, tôi phát hiện ra rằng tập hợp các trình giữ chỗ hiện tại không đủ cho nhu cầu thực tế và phải được mở rộng, cho cả các cấu trúc dữ liệu phức tạp, như mảng và thậm chí cả từ khóa hoặc mã định danh SQL, đôi khi phải được thêm vào truy vấn động cũng vậy, nhưng một nhà phát triển không có vũ khí cho trường hợp như vậy và buộc phải quay lại nối chuỗi nhưng đó là vấn đề của một câu hỏi khác).

Điều thú vị là, tranh cãi của câu hỏi này bị kích động bởi tính chất gây tranh cãi của Stack Overflow. Ý tưởng của trang web là sử dụng các câu hỏi cụ thể từ những người dùng hỏi trực tiếp để đạt được mục tiêu là có cơ sở dữ liệu các câu trả lời cho mục đích chung phù hợp với những người dùng đến từ tìm kiếm . Ý tưởng này không phải là xấu cho mỗi gia nhập , nhưng nó bị lỗi trong một tình huống như thế này: khi người dùng yêu cầu một câu hỏi rất hẹp , đặc biệt là để có được một cuộc tranh cãi trong một tranh chấp với một đồng nghiệp (hoặc quyết định nếu nó có giá trị để cấu trúc lại mã). Trong khi hầu hết những người tham gia có kinh nghiệm đang cố gắng viết câu trả lời, hãy ghi nhớ nhiệm vụ về tổng thể Stack Overflow, làm cho câu trả lời của họ tốt cho càng nhiều người đọc càng tốt, chứ không chỉ OP.


10
Không trả lời câu hỏi
edc65

Hầu hết các cơ sở dữ liệu đều phát hiện các truy vấn đã được sử dụng, được tham số hóa bằng đẳng thức chuỗi SQL, vì vậy phương pháp xử lý chuẩn bị và sử dụng cũ dường như đã lỗi thời đối với tôi. Những tay cầm này chỉ có thể được sử dụng trong một phạm vi nhất định và yêu cầu mã hóa để theo dõi tay cầm. Theo ý kiến ​​của tôi, các truy vấn được tham số hóa nên được sử dụng trực tiếp để các kế hoạch truy vấn có thể được sử dụng lại mà không cần xử lý theo dõi và thậm chí trên các ứng dụng khác nhau.
Erik Hart

15

Đừng chỉ nghĩ về các cân nhắc về bảo mật hoặc an toàn kiểu.

Lý do bạn sử dụng truy vấn được tham số hóa là để cải thiện hiệu suất ở cấp cơ sở dữ liệu. Từ góc độ cơ sở dữ liệu, một truy vấn được tham số hóa là một truy vấn trong bộ đệm SQL (để sử dụng thuật ngữ của Oracle mặc dù tôi tưởng tượng rằng tất cả các cơ sở dữ liệu đều có một khái niệm tương tự trong nội bộ). Vì vậy, cơ sở dữ liệu có thể chứa một lượng truy vấn nhất định trong bộ nhớ, được chuẩn bị và sẵn sàng thực thi. Những truy vấn này không cần phải được phân tích cú pháp và sẽ nhanh hơn. Các truy vấn thường xuyên chạy thường sẽ nằm trong bộ đệm và sẽ không cần phân tích cú pháp mỗi khi chúng được sử dụng.

TRỪ KHI

Ai đó không sử dụng truy vấn tham số hóa. Trong trường hợp này, bộ đệm liên tục bị tuôn ra bởi một luồng các truy vấn gần giống hệt nhau, mỗi truy vấn trong số đó cần được phân tích cú pháp và chạy bởi cơ sở dữ liệu và hiệu suất bị ảnh hưởng toàn diện vì các truy vấn chạy thường xuyên cuối cùng cũng được phân tích lại nhiều lần. ngày. Tôi đã điều chỉnh cơ sở dữ liệu để kiếm sống và đây là một trong những nguồn lợi nhuận thấp nhất.

HIỆN NAY

Để trả lời câu hỏi của bạn, NẾU truy vấn của bạn có một số lượng nhỏ các giá trị số riêng biệt, bạn có thể sẽ không gây ra sự cố và thực tế có thể cải thiện hiệu suất một cách nhanh chóng. Tuy nhiên, NẾU có thể có hàng trăm giá trị và truy vấn được gọi rất nhiều, bạn sẽ ảnh hưởng đến hiệu suất của hệ thống, vì vậy đừng làm điều đó.

Có, bạn có thể tăng bộ đệm SQL nhưng cuối cùng nó luôn phải trả giá bằng các cách sử dụng quan trọng khác cho bộ nhớ như bộ nhớ đệm Chỉ mục hoặc Dữ liệu. Về mặt đạo đức, hãy sử dụng các truy vấn được tham số hóa khá tôn giáo để bạn có thể tối ưu hóa cơ sở dữ liệu của mình và sử dụng nhiều bộ nhớ máy chủ hơn cho những thứ quan trọng ...


8

Để thêm một số thông tin vào câu trả lời Maciek:

Có thể dễ dàng thay đổi thông tin văn hóa của ứng dụng .NET bên thứ ba bằng cách gọi hàm chính của assembly bằng cách phản ánh:

using System;
using System.Globalization;
using System.Reflection;
using System.Threading;

namespace ConsoleApplication2
{
  class Program
  {
    static void Main(string[] args)
    {
      Assembly asm = Assembly.LoadFile(@"C:\BobbysApp.exe");
      MethodInfo mi = asm.GetType("Test").GetMethod("Main");
      mi.Invoke(null, null);
      Console.ReadLine();
    }

    static Program()
    {
      InstallBobbyTablesCulture();
    }

    static void InstallBobbyTablesCulture()
    {
      CultureInfo bobby = (CultureInfo)CultureInfo.InvariantCulture.Clone();
      bobby.DateTimeFormat.ShortDatePattern = @"yyyy-MM-dd'' OR ' '=''";
      bobby.DateTimeFormat.LongTimePattern = "";
      bobby.NumberFormat.NegativeSign = "1 OR 1=1 OR 1=";
      Thread.CurrentThread.CurrentCulture = bobby;
    }
  }
}

Điều này chỉ hoạt động nếu chức năng Chính của BobbysApp là công khai. Nếu Main không công khai, bạn có thể gọi các chức năng công khai khác.


1
Bạn thậm chí không cần phải làm điều đó bằng mã. Bạn có thể thêm tiêm trực tiếp trong Cài đặt khu vực của Windows. Hãy xem câu trả lời của tôi.
Kaspars Ozols

2
Ai có thể thay đổi cài đặt máy chủ hoặc ai có thể chà mã như vậy trong máy chủ? Nếu một người có thể làm điều đó trong máy chủ của bạn, anh ta không cần SQL Injection để phá hủy dữ liệu.
Reza Aghaei

7

Theo ý kiến ​​của tôi nếu bạn có thể đảm bảo rằng tham số bạn đang làm việc sẽ không bao giờ chứa một chuỗi thì nó sẽ an toàn nhưng tôi sẽ không làm điều đó trong mọi trường hợp. Ngoài ra, bạn sẽ thấy hiệu suất giảm nhẹ do thực tế là bạn đang thực hiện nối. Câu hỏi tôi sẽ hỏi bạn là tại sao bạn không muốn sử dụng các tham số?


1
Không phải là tôi không muốn sử dụng tham số mà là tôi đang sử dụng tham số. Một đồng nghiệp đã viết mã như thế này mà tôi đã sửa đổi để được tham số hóa ngày hôm nay, điều này khiến tôi nghĩ đến câu hỏi.
johnnyRose

Đồng ý. Tuyệt quá. Đó là một phương pháp hay nhất để sử dụng các tham số. Bằng cách này, bạn không phải lo lắng về những thứ như tiêm sql. Ngoài ra, nếu bạn đang xây dựng một truy vấn động, bạn cũng có thể sử dụng các tham số bất kể truy vấn của bạn phức tạp đến mức nào. Đơn giản chỉ cần sử dụng kiểu @ 1 ... @ n khi xây dựng chúng. Và nối chúng vào bộ sưu tập tham số với giá trị mong muốn.
Tối đa

@johnyRose Có một điểm nữa để sử dụng các tham số: các chương trình đang phát triển và thay đổi. Bạn chỉ có thể sử dụng nối cho chuỗi nhưng điều đó không đảm bảo rằng ai đó thực hiện tái cấu trúc thay đổi một số kiểu tham số và những thay đổi đó có thể dẫn đến lỗ hổng SQL Injection.
lerthe61

3

Nó ổn nhưng không bao giờ an toàn .. và bảo mật luôn phụ thuộc vào các đầu vào, ví dụ: nếu đối tượng đầu vào là TextBox, những kẻ tấn công có thể làm điều gì đó khó khăn vì hộp văn bản có thể chấp nhận chuỗi, vì vậy bạn phải đặt một số loại xác nhận / chuyển đổi để có thể ngăn người dùng nhập sai. Nhưng có điều, nó không an toàn. Đơn giản là như vậy.


Đó là một chuỗi mặc dù. Tôi đang nói về các kiểu dữ liệu khác, như số nguyên, boolean hoặc lịch ngày.
johnnyRose

@johnnyRose Yup, tôi đã thấy một ví dụ rất hay ở trên mà bạn đánh dấu là đã trả lời bởi Kaspards .. và câu trả lời tuyệt vời khi anh ấy sử dụng kiểu dữ liệu datetime làm ví dụ, điều này không phổ biến. :) Tôi hy vọng bạn đã tin rằng nó không phải là an toàn và tốt hơn để tham số sử dụng trong bất kỳ loại kiểu dữ liệu
japzdivino

Tôi chưa bao giờ thực sự nghi ngờ việc sử dụng các thông số sẽ an toàn hơn. Câu hỏi của tôi đề cập đến các triển khai được đánh máy mạnh.
johnnyRose

Yup .. tôi đồng ý. và đó cũng là câu hỏi lớn mà độc giả có thể giúp tương lai :)
japzdivino

-2

Không, bạn có thể bị tấn công SQL injection theo cách đó. Tôi đã viết một bài báo cũ bằng tiếng Thổ Nhĩ Kỳ cho thấy cách làm ở đây . Ví dụ bài viết trong PHP và MySQL nhưng khái niệm hoạt động giống nhau trong C # và SQL Server.

Về cơ bản bạn tấn công theo cách sau. Hãy coi bạn có một trang hiển thị thông tin theo giá trị id số nguyên. Bạn không tham số này về giá trị, như bên dưới.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=24

Được rồi, tôi giả sử bạn đang sử dụng MySQL và tôi tấn công theo cách sau.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII((SELECT%20DATABASE()))

Lưu ý rằng ở đây giá trị được đưa vào không phải là chuỗi. Chúng tôi đang thay đổi giá trị char thành int bằng cách sử dụng hàm ASCII. Bạn có thể thực hiện điều tương tự trong SQL Server bằng cách sử dụng "CAST (YourVarcharCol AS INT)".

Sau đó, tôi sử dụng các hàm chiều dài và chuỗi con để tìm về tên cơ sở dữ liệu của bạn.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=LEN((SELECT%20DATABASE()))

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR(SELECT%20DATABASE(),1,1))

Sau đó, sử dụng tên cơ sở dữ liệu, bạn bắt đầu lấy tên bảng trong cơ sở dữ liệu.

http://localhost/sqlEnjeksiyon//instructors.aspx?id=ASCII(SUBSTR((SELECT table_name FROM INFORMATION_SCHEMA.TABLES LIMIT 1),1,1))

Tất nhiên bạn phải tự động hóa quá trình này, vì bạn chỉ nhận được MỘT ký tự cho mỗi truy vấn. Nhưng bạn có thể dễ dàng tự động hóa nó. Bài viết của tôi cho thấy một ví dụ trong watir . Chỉ sử dụng một trang và không phải giá trị ID được tham số hóa. Tôi có thể tìm hiểu mọi tên bảng trong cơ sở dữ liệu của bạn. Sau đó, tôi có thể tìm kiếm các bảng quan trọng. Nó sẽ mất thời gian nhưng nó có thể làm được.


2
Câu hỏi của tôi đề cập đến một ngôn ngữ được đánh máy mạnh. Mặc dù lời giải thích của bạn rất tốt cho các ngôn ngữ có cách nhập linh hoạt, giá trị được đưa vào vẫn là một chuỗi.
johnnyRose

Không có giá trị nào được đưa vào là số nguyên. Bạn lấy char và thay đổi nó thành số nguyên bằng cách sử dụng hàm ASCII MySQL. Bạn làm điều tương tự trong SQL Server sử dụng CAST (YourCharValue AS INT)
Atilla Ozgur

Ý tôi là một cái gì đó như thế này:public void QuerySomething(int id) { // this will only accept an integer }
johnnyRose

-3

Chà ... chắc chắn một điều: Bảo mật KHÔNG ĐƯỢC, khi bạn nối một chuỗi (do người dùng lấy) với chuỗi lệnh SQL của bạn. Không có vấn đề gì bất cứ khi nào mệnh đề where đề cập đến một Số nguyên hoặc bất kỳ loại nào; có thể xảy ra tiêm.

Điều quan trọng trong SQL Injection là kiểu dữ liệu của biến được sử dụng để nhận giá trị từ người dùng.

Giả sử chúng ta có một số nguyên trong mệnh đề where và:

  1. biến người dùng là một chuỗi. Vậy thì ok, nó không phải là rất dễ dàng để tiêm (sử dụng UNION) nhưng nó rất dễ dàng bỏ qua bằng cách sử dụng 'OR 1 = 1' - như các cuộc tấn công ...

  2. Nếu biến người dùng là một số nguyên. Sau đó, một lần nữa, chúng tôi có thể 'kiểm tra' sức mạnh của hệ thống bằng cách vượt qua kiểm tra số lượng lớn bất thường để tìm sự cố hệ thống hoặc thậm chí đối với lỗi tràn bộ đệm ẩn (trên chuỗi cuối cùng) ...;)

Có thể các tham số đối với truy vấn hoặc (thậm chí tốt hơn - imo) đối với Thủ tục được lưu trữ không phải là an toàn 100% về Đe dọa, nhưng chúng là biện pháp ít bắt buộc nhất (hoặc là biện pháp cơ bản nếu bạn muốn) để giảm thiểu chúng.


Tôi nghĩ bạn có thể đã hiểu sai câu hỏi. Tôi đang nói về các loại không phải chuỗi.
johnnyRose

Xin chào JonnyRose ... cảm ơn bạn đã lưu ý. Tôi hiểu câu hỏi của bạn nhưng tôi chỉ đặt câu trả lời của tôi ở dạng tổng quát hơn. Đối với trường hợp không phải chuỗi, vui lòng kiểm tra điểm (2) của tôi. ;)
Andreas Venieris,
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.