2013-03-21 51 views
56

Để bắt đầu điều này, tôi nhận thức được rằng các truy vấn được tham số hóa là lựa chọn tốt nhất, nhưng tôi hỏi điều gì làm cho chiến lược tôi trình bày dưới đây dễ bị tổn thương. Mọi người nhấn mạnh giải pháp dưới đây không hiệu quả, vì vậy tôi đang tìm một ví dụ về lý do tại sao nó lại không thành công.Làm thế nào có thể vệ sinh mà thoát khỏi dấu nháy đơn bị đánh bại bởi SQL injection trong SQL Server?

Nếu SQL động được xây dựng trong mã bằng cách sử dụng thoát sau đây trước khi được gửi đến một máy chủ SQL, loại tiêm nào có thể đánh bại điều này?

string userInput= "N'" + userInput.Replace("'", "''") + "'" 

Câu hỏi tương tự đã được trả lời here, nhưng tôi không tin bất kỳ câu trả lời nào được áp dụng tại đây.

Việc thoát dấu nháy đơn bằng dấu "\" không thể thực hiện được trong SQL Server.

Tôi tin rằng SQL Smuggling với Unicode (được vạch ra here) sẽ bị cản trở bởi thực tế là chuỗi được tạo ra được đánh dấu là Unicode bởi N trước dấu nháy đơn. Theo như tôi biết, không có bộ ký tự khác mà SQL Server sẽ tự động dịch sang một trích dẫn duy nhất. Nếu không có một trích dẫn duy nhất, tôi không tin rằng tiêm là có thể.

Tôi không tin rằng Cắt ngắn chuỗi cũng là một vector khả thi. SQL Server chắc chắn sẽ không thực hiện cắt xén vì kích thước tối đa cho một nvarchar là 2GB according to microsoft. Chuỗi 2 GB không khả thi trong hầu hết các trường hợp và không thể xảy ra trong tôi.

Thứ hai theo thứ tự tiêm có thể là có thể, nhưng là nó có thể nếu:

  1. Tất cả dữ liệu đi sâu vào cơ sở dữ liệu được vệ sinh bằng cách sử dụng phương pháp trên
  2. giá trị từ cơ sở dữ liệu không bao giờ được nối vào SQL động (tại sao bạn sẽ làm điều đó dù sao, khi bạn chỉ có thể tham khảo giá trị bảng trong phần tĩnh của bất kỳ chuỗi SQL động nào?).

Tôi không cho rằng điều này tốt hơn hoặc thay thế cho việc sử dụng truy vấn được tham số hóa, nhưng tôi muốn biết cách tôi vạch ra là dễ bị tổn thương. Bất kỳ ý tưởng?

+1

No. Bạn vẫn dễ bị tấn công dưới dạng: "userInput' khi' userInput' là '0 ; DROP BẢNG OhNo; '. – Yuck

+8

Điều này không có ý nghĩa. Trong ví dụ trên, đầu vào của người dùng của bạn sẽ được vệ sinh thành N'0; DROP BẢNG OhNo; ' trước khi bị xử tử. – GBleaney

+3

Điều này chỉ áp dụng cho các biến chuỗi khử trùng. Những thứ như "int" không cần phải được khử trùng nếu chúng được đúc dưới dạng int trước khi được thêm vào truy vấn. Bất kể, tôi chỉ hỏi về việc vệ sinh dây ngay bây giờ. Ngoài ra, không cần phải thô lỗ ở đây. Nếu bạn có thể nghĩ ra một cách mà điều này không an toàn, tôi rất muốn biết. – GBleaney

Trả lời

33

Có một vài trường hợp chức năng thoát này sẽ không thành công. Điều hiển nhiên nhất là khi một báo giá không được sử dụng:

string table= "\"" + table.Replace("'", "''") + "\"" 
string var= "`" + var.Replace("'", "''") + "`" 
string index= " " + index.Replace("'", "''") + " " 
string query = "select * from `"+table+"` where name=\""+var+"\" or id="+index 

Trong trường hợp này, bạn có thể "thoát ra" bằng cách sử dụng dấu nháy kép, dấu kiểm. Trong trường hợp cuối cùng không có gì để "thoát ra", vì vậy bạn chỉ có thể viết 1 union select password from users-- hoặc bất cứ điều gì sql tải trọng kẻ tấn công mong muốn.

Điều kiện tiếp theo mà chức năng thoát này sẽ thất bại là nếu một tiểu chuỗi được thực hiện sau khi các chuỗi thoát (và lỗ hổng có Tôi đã tìm thấy như thế này trong tự nhiên):

string userPassword= userPassword.Replace("'", "''") 
string userName= userInput.Replace("'", "''") 
userName = substr(userName,0,10) 
string query = "select * from users where name='"+userName+"' and password='"+userPassword+"'"; 

Trong trường hợp này, tên người dùng là abcdefgji' sẽ được chuyển thành abcdefgji'' bằng chức năng thoát và sau đó quay lại thành abcdefgji' bằng cách lấy chuỗi con. Điều này có thể được khai thác bằng cách đặt giá trị mật khẩu cho bất kỳ câu lệnh sql nào, trong trường hợp này, or 1=1-- sẽ được hiểu là sql và tên người dùng sẽ được hiểu là abcdefgji'' and password=. Truy vấn kết quả như sau:

select * from users where name='abcdefgji'' and password=' or 1=1-- 

T-SQL và các kỹ thuật tiêm sql tiên tiến khác đã được đề cập. Advanced SQL Injection In SQL Server Applications là một bài báo tuyệt vời và bạn nên đọc nó nếu bạn chưa có.

Vấn đề cuối cùng là tấn công unicode. Lớp lỗ hổng này phát sinh do hàm thoát không nhận thức được mã hóa mulit-byte, và điều này có thể là used by an attacker to "consume" the escape character. Việc thêm một "N" vào chuỗi sẽ không giúp ích gì, vì điều này không ảnh hưởng đến giá trị của các ký tự nhiều byte sau này trong chuỗi. Tuy nhiên, kiểu tấn công này rất không phổ biến vì cơ sở dữ liệu phải được cấu hình để chấp nhận các chuỗi unicode GBK (và tôi không chắc chắn rằng MS-SQL có thể làm điều này).

Tiêm mã thứ hai vẫn có thể, mẫu tấn công này được tạo bằng cách tin tưởng các nguồn dữ liệu do kẻ tấn công kiểm soát. Thoát được sử dụng để đại diện cho các ký tự điều khiển là ký tự chữ của chúng. Nếu nhà phát triển quên thoát khỏi giá trị thu được từ số select và sau đó sử dụng giá trị này trong truy vấn khác thì bam kẻ tấn công sẽ có một dấu trích dẫn ký tự theo nghĩa đen theo ý của họ.

Kiểm tra mọi thứ, không tin tưởng gì cả.

+1

Trong khi tôi đồng ý chơi với bảo mật thay vì truy vấn tham số là xấu, nếu bạn đọc cẩn thận câu hỏi của mình, ông đã lưu ý một số bước ông sẽ thực hiện để "đảm bảo" an toàn. 1) anh ta đảm bảo một giá trị số thực sự là một giá trị số để id tiêm trong ví dụ của bạn sẽ thất bại 2) anh ta hỏi về SQL Server mà chỉ chấp nhận ''' như dấu phân cách chuỗi. Sử dụng dấu trích dẫn hoặc dấu ngoặc kép sẽ không giúp kẻ tấn công –

+0

@Nikola Radosavljević có, nhưng ngược lại và thiếu dấu ngoặc kép vẫn có thể là một vấn đề tùy thuộc vào cách anh ta cấy ghép kiểm tra này. Rõ ràng bài viết này là từ quan điểm của một kẻ tấn công không phải là một hậu vệ. Quốc phòng nổi tiếng và không quan tâm. – rook

+2

Mã trong câu hỏi không dễ bị tấn công. Đây là một câu trả lời đúng như một hướng dẫn chung để thoát khỏi các chuỗi ký tự và nó vừa chính xác vừa thú vị; nhưng các kịch bản được liệt kê sẽ không thể thỏa hiệp dòng mã trong câu hỏi ban đầu. Liên quan đến các cuộc tấn công bằng tay thứ hai, nó có thể xảy ra cho dù văn bản ban đầu được chèn với một tham số hoặc là một chữ nếu nó có chứa một ký tự trích dẫn. – Rob

8

Using query parameters là tốt hơn, dễ dàng hơn và nhanh hơn so với dấu ngoặc kép thoát.


Hãy bình luận của bạn, tôi thấy rằng bạn đã thừa nhận tham số, nhưng nó đáng được chú trọng. Tại sao bạn muốn sử dụng thoát khi bạn có thể tham số hóa?

Trong Advanced SQL Injection In SQL Server Applications, tìm kiếm từ "thay thế" trong văn bản và từ đó đọc một số ví dụ mà nhà phát triển vô tình cho phép các cuộc tấn công SQL injection ngay cả sau khi thoát đầu vào của người dùng.


Có một trường hợp cạnh nơi thoát dấu ngoặc kép với \ kết quả trong một lỗ hổng, vì \ trở thành một nửa của một nhân vật đa byte có giá trị trong một số bộ ký tự. Nhưng điều này không áp dụng cho trường hợp của bạn vì \ không phải là ký tự thoát.

Như những người khác đã chỉ ra, bạn cũng có thể thêm nội dung động vào SQL của bạn cho một thứ khác ngoài chuỗi ký tự hoặc theo ngày tháng. Số nhận dạng bảng hoặc cột được phân tách bằng " trong SQL hoặc [] trong Microsoft/Sybase. Tất nhiên các từ khóa SQL không có bất kỳ dấu phân tách nào. Đối với những trường hợp này, tôi khuyên bạn nên các danh sách trắng các giá trị để nội suy.

Điểm mấu chốt là thoát một biện pháp phòng thủ hiệu quả, nếu bạn có thể đảm bảo rằng bạn làm điều đó một cách nhất quán. Đó là rủi ro: rằng một trong những nhóm các nhà phát triển ứng dụng của bạn có thể bỏ qua một bước và làm một số nội suy chuỗi không an toàn.

Tất nhiên, điều này cũng đúng với các phương pháp khác, như tham số hóa. Chúng chỉ có hiệu quả nếu bạn thực hiện chúng một cách nhất quán. Nhưng tôi thấy việc sử dụng các thông số dễ dàng hơn, để tìm ra loại thoát đúng. Và các nhà phát triển có nhiều khả năng sử dụng một phương pháp thuận tiện và không làm chậm chúng.

+2

Khi tôi nêu trong dòng đầu tiên của bài đăng, tôi biết rõ điều này. Tôi chỉ hỏi nếu có một số lý do cụ thể mà những gì tôi vạch ra là không an toàn. – GBleaney

+1

Đó là một nguồn tài nguyên tuyệt vời, nhưng các vấn đề có thể được đề xuất trong đó không thực sự là một vấn đề ở đây. Thứ nhất, việc xây dựng các trích dẫn bằng cách sử dụng phương thức "char (0x63)" là vô ích, bởi vì câu lệnh đó sẽ được hiểu là một chuỗi và không được thực thi. Đối với lệnh SQL injection thứ hai, tôi đã giải quyết điều đó trong bài đăng gốc. – GBleaney

3

Lỗi SQL xảy ra nếu người dùng cung cấp đầu vào được hiểu là lệnh. Lệnh này có nghĩa là bất kỳ thứ gì không được hiểu là một chữ số được công nhận là data type.

Bây giờ, nếu bạn chỉ sử dụng dữ liệu đầu vào của người dùng trong các chuỗi dữ liệu, thì đầu vào của người dùng sẽ chỉ được hiểu là khác với dữ liệu chuỗi nếu nó có thể rời khỏi ngữ cảnh chuỗi. Đối với chuỗi ký tự hoặc chuỗi ký tự Unicode, đó là dấu ngoặc kép đơn bao quanh dữ liệu theo nghĩa đen trong khi dấu nháy đơn được nhúng cần phải được biểu diễn bằng hai dấu ngoặc đơn. Vì vậy, để để lại một ngữ cảnh chuỗi chữ, người ta sẽ cần phải cung cấp một dấu nháy đơn (sic) vì hai dấu nháy đơn được hiểu là dữ liệu chuỗi ký tự và không phải là dấu phân cách kết thúc bằng chữ. Vì vậy, nếu bạn đang thay thế bất kỳ dấu nháy đơn nào trong dữ liệu do người dùng cung cấp bởi hai dấu nháy đơn thì người dùng sẽ không thể rời khỏi ngữ cảnh chuỗi ký tự.

2

Có thể không có cách an toàn 100% nếu bạn đang thực hiện nối chuỗi. Những gì bạn có thể làm là cố gắng kiểm tra kiểu dữ liệu cho mỗi tham số và nếu tất cả các tham số vượt qua xác thực như vậy thì hãy tiếp tục thực hiện. Ví dụ: nếu tham số của bạn phải nhập int và bạn đang nhận được một thứ không thể chuyển đổi thành int thì chỉ cần từ chối tham số đó.

Điều này không hoạt động nếu bạn chấp nhận thông số nvarchar.

Như những người khác đã chỉ ra. Cách an toàn nhất là sử dụng truy vấn được tham số hóa.

16

Với một số quy định bổ sung, cách tiếp cận của bạn ở trên không dễ bị tấn công SQL injection. Các vector chính của tấn công để xem xét là SQL buôn lậu. SQL Smuggling xảy ra khi các ký tự unicode tương tự được dịch theo kiểu không mong đợi (ví dụ: `change to '). Có một số vị trí nơi ngăn xếp ứng dụng có thể dễ bị tấn công vào SQL Smuggling.

  • Ngôn ngữ lập trình có xử lý các chuỗi unicode một cách thích hợp không? Nếu ngôn ngữ không phải là nhận thức unicode, nó có thể xác định sai một byte trong một ký tự unicode như một báo giá duy nhất và thoát nó.

  • Thư viện cơ sở dữ liệu khách hàng (ví dụ: ODBC, v.v.) có xử lý các chuỗi unicode một cách thích hợp không? System.Data.SqlClient trong khuôn khổ .Net, nhưng làm thế nào về các thư viện cũ từ thời kỳ 95 của windows? Thư viện ODBC của bên thứ ba thực sự tồn tại. Điều gì xảy ra nếu trình điều khiển ODBC không hỗ trợ unicode trong chuỗi truy vấn?

  • DB có xử lý đầu vào chính xác không? Phiên bản hiện tại của SQL là miễn dịch giả sử bạn đang sử dụng N '', nhưng những gì về SQL 6,5? SQL 7.0? Tôi không biết về bất kỳ lỗ hổng cụ thể nào, tuy nhiên điều này không có trên radar cho các nhà phát triển trong những năm 1990.

  • Lỗi tràn bộ đệm? Một mối quan tâm khác là chuỗi được trích dẫn dài hơn chuỗi gốc. Trong đó phiên bản của Sql Server là giới hạn 2GB cho đầu vào được giới thiệu? Trước đó giới hạn là gì? Trên các phiên bản cũ hơn của SQL, điều gì đã xảy ra khi truy vấn vượt quá giới hạn? Có bất kỳ giới hạn tồn tại trên chiều dài của một truy vấn từ quan điểm của thư viện mạng? Hoặc trên chiều dài của chuỗi trong ngôn ngữ lập trình?

  • Có cài đặt ngôn ngữ nào ảnh hưởng đến so sánh được sử dụng trong hàm Replace() không?. Net luôn so sánh nhị phân cho hàm Replace(). Sẽ luôn luôn như vậy? Điều gì sẽ xảy ra nếu một phiên bản tương lai của .NET hỗ trợ ghi đè hành vi đó ở cấp app.config? Điều gì sẽ xảy ra nếu chúng ta sử dụng regexp thay vì Replace() để chèn một dấu nháy đơn? Cài đặt miền địa phương của máy tính có ảnh hưởng đến so sánh này không? Tuy nhiên, nếu thay đổi hành vi xảy ra, nó có thể không dễ bị chèn ép sql, nó có thể vô tình chỉnh sửa chuỗi bằng cách thay đổi một ký tự uni-code giống như một trích dẫn đơn thành một báo giá duy nhất trước khi nó đạt đến DB.

Vì vậy, giả sử bạn đang sử dụng hàm System.String.Replace() trong C# trên phiên bản hiện tại của .Net với thư viện SqlClient tích hợp dựa vào phiên bản hiện tại (2005-2012) của SQL máy chủ, thì cách tiếp cận của bạn không dễ bị tổn thương. Khi bạn bắt đầu thay đổi mọi thứ, thế thì không lời hứa nào có thể được thực hiện. Cách tiếp cận truy vấn được tham số hóa là cách tiếp cận chính xác cho hiệu quả, hiệu suất và (trong một số trường hợp) để bảo mật.

CẢNH BÁO Các nhận xét trên không phải là sự chứng thực của kỹ thuật này. Có một số lý do rất tốt khác tại sao phương pháp này sai để tạo ra SQL. Tuy nhiên, chi tiết chúng nằm ngoài phạm vi của câu hỏi này.

KHÔNG SỬ DỤNG KỸ THUẬT NÀY CHO PHÁT TRIỂN MỚI.

KHÔNG SỬ DỤNG KỸ THUẬT NÀY CHO PHÁT TRIỂN MỚI.

KHÔNG SỬ DỤNG KỸ THUẬT NÀY CHO PHÁT TRIỂN MỚI.

+0

Nếu không phải là kỹ thuật này, thì tôi nên sử dụng cái gì cho 'TẠO ĐĂNG NHẬP 'trong phát triển mới? – binki

3

Tiêm SQL có thể xảy ra thông qua unicode. Nếu ứng dụng web có URL như sau:

http://mywebapp/widgets/?Code=ABC

mà tạo ra SQL như select * from widget nơi Mã = 'ABC'

nhưng một hacker vào đây:

http://mywebapp/widgets/?Code=ABC%CA%BC;drop bảng widgets--

SQL sẽ trông giống như chọn * từ tiện ích con nơi Code = 'ABC'; tiện ích bảng thả-- '

và SQL Server sẽ chạy hai câu lệnh SQL. Một để làm việc lựa chọn và một để làm thả. Mã của bạn có thể chuyển đổi mã hóa% CA% BC được mã hóa url thành UICBC unicode, đó là "dấu nháy đơn chữ cái sửa đổi". Hàm Replace trong .Net sẽ KHÔNG coi đó là một dấu nháy đơn. Tuy nhiên Microsoft SQL Server xử lý nó như một trích dẫn duy nhất.Dưới đây là ví dụ có thể cho phép SQL Injection:

string badValue = ((char)0x02BC).ToString(); 
badValue = badValue + ";delete from widgets--"; 
string sql = "SELECT * FROM WIDGETS WHERE ID=" + badValue.Replace("'","''"); 
TestTheSQL(sql); 
+0

Điều này sẽ hoạt động: string sql = "SELECT * FROM WIDGETS WHERE ID = '" + badValue.Replace ("'", "''") + "'"; – linjunhalida