2009-12-02 59 views
6

我想在這裏簡單地證明了這個簡單的功能不夠好,以防止在世界上每一個SQL注入:機器證明SQL注入

Function CleanForSQL(ByVal input As String) As String 
    Return input.Replace("'", "''") 
End Function 

這裏是我們的應用程序的一個典型INSERT語句:

Database.DBUpdate("UPDATE tblFilledForms SET Text1 = '" + CleanForSQL(txtNote.Text) + "' WHERE FilledFormID = " + DGVNotes.SelectedRows(0).Cells("FilledFormID").Value.ToString) 

我知道它不安全,因爲使用谷歌搜索和查找StackOverflow.com上的其他問題。 Here是我發現的一個問題,其中所有功能(如上面提到的功能)都是無關緊要的。

因此,基於我掛了後,只需鍵入

「CHR(8);更新tblMaint SET值1 = 2 WHERE VALUEID = 2--

到txtNote應該足以在整個tblFilledForms表的text1清除每一個值,然後更新tblmaint表的第二行是2是否正確?

這裏什麼應該發生的是,VB將其解釋爲

UPDATE tblFilledForms SET文本1 = '''CHR(8);更新tblMaint SET值1 = 2 WHERE VALUEID = 2-- 'WHERE FilledFormID = 5120327

並將其發送到SQL將實習生執行CHR(8)以擦除第三',這將產生

UPDATE tblFilledForms SET Text1 ='';更新tblMaint SET Value1 = 2 WHERE ValueID = 2--'WHERE FilledFormID = 5120327

對數據庫實際執行正確嗎?

然後,我從剪貼板中複製了一個Chr(8),並將文本框中的Chr(8)替換爲剪貼板內容,但仍然是禁用。它將整個字符串直接放入字段中,不存在問題。

那麼我在這裏做錯了什麼?或者我還能做些什麼來打破它?

技術和背景: 我使用MS SQL Server 2005中,和VB .NET 2005 在數據庫中的文本1場是一個varchar(600)字段(不要問我爲什麼它不MAX,它是毫無意義的,我知道) 表中有某些觸發器可以防止這種大規模更新,並且如果注入實際上正常工作時會拋出一些錯誤。

PS。我知道參數化查詢是去這裏的方式,我不在尋找像「我不明白爲什麼它不起作用,但參數化查詢是要走的路」這樣的答案。我正在尋找證明我們的軟件被破壞的能力,並且我們需要使用更好的原則來重寫它。

對於任何人閱讀這個問題想弄清楚如何更好地過濾文本字段,答案是不!使用參數!他們更好,更安全,更容易!

+5

對同一段落中的威脅人和寫作原則而不是原則的投降。 – 2009-12-02 17:20:27

+0

你的Chr(8)最終在一個字符串內部,這就是爲什麼SQL不評估它。 – 2009-12-02 17:21:18

+6

@Vinko我認爲這不公平,他只是設定了答案的指導方針。所以,不要得到大量的答案都說同樣的事情,他得到1或2,告訴他他想要什麼。 – Zoidberg 2009-12-02 17:22:43

回答

6

Chr(8)是引用的文字字符串的一部分,就像更新語句一樣,所以SQL Server不會將其解釋爲函數調用。有了這個例子中,文本1將被設置爲文本值:

'Chr(8); update tblMaint SET Value1 = 2 WHERE ValueID = 2-- 

(是的,包括單引號)

所以,用這個例子中,你的代碼安全。大多數SQL注入攻擊都是偶然的,因爲不能通過來驗證和引用值,在正確引用的SQL語句中並沒有固有的不安全因素。

+0

+1,因爲你的回答可能會成爲這個問題的最終答案。 – Jrud 2009-12-02 22:37:54

0

我覺得你的問題是,不執行Chr(8),你需要找到另一種方式來獲得領先的報價大關。

+0

是的,我有...任何建議? – Jrud 2009-12-02 17:31:59

1

你沒有做錯什麼。這是SQL Server分析字符串的方式。第一個報價打開字符串,然後你立即跟着一個轉義報價,接着是Chr(8)。

作爲一個練習,如果在SQL Server中運行這個練習,會發生什麼情況:SELECT '''Hello'?在這種情況下,正在應用完全相同的分析規則。

+0

是的,這正是發生了什麼,我明白。但我仍然需要以某種方式打破它... – Jrud 2009-12-02 17:24:56

+0

你不需要打破它 - 你只需要證明你的技術適用於所有情況,或不。 – 2009-12-02 17:26:54

+0

是的,如果它適用於所有情況,那麼通過消除就可以排除反證。 – Jrud 2009-12-02 17:29:50

4

您的CleanForSQL方法僅處理字符串情況。當你不使用字符串而是使用INT時會發生什麼?在這種情況下,將沒有結束時刻結束,因此注射仍然會發生。考慮下面這個例子......

Database.DBUpdate("UPDATE tblFilledForms SET Int1 = " + CleanForSQL(txtNote.Text) + " WHERE FilledFormID = " + DGVNotes.SelectedRows(0).Cells("FilledFormID").Value.ToString) 
在這種情況下

,剛進入下面的工作......

0; update tblMaint SET Value1 = 2 WHERE ValueID = 2--

+0

我們不允許用戶將任何數字輸入到首先未被首先檢查的文本字段中。如果它是一個數字字段,我相信這會中斷,但我們不使用這種方法。這是嚴格的字符串。 – Jrud 2009-12-02 17:31:05

+4

不要忘記,它可能是ID號碼或查詢字符串中的內容 - 不僅僅是文本框。我遇到的大部分注入都是查詢字符串中未經檢查的變量,而不是表單字段。 – 2009-12-02 17:38:55

+2

+1查詢字符串 - 不要忘記任何人都可以創建一個僞造的表單發佈到您的頁面。我不知道如何設置DGVNotes.SelectedRows(0).Cells(「FilledFormID」),但是如果它來自瀏覽器AT ALL,則可以注入SQL。我知道你總是檢查你的數字字段,但如果你忘記了,它會打開一個洞。 – 2009-12-02 17:59:08

3

斯科特·艾維有一個可以打破它的經典案例,缺乏報價保護數字輸入。 (加1)

根據語言以及字符串被「清理」和正在使用的數據庫的位置,您的直接風險是它們的語言允許字符串被轉義。此時,您試圖避免穿越的單引號出錯

\'; DROP yourTable; - => \''; DROP yourTable; -

那進入你的SQL字符串作爲

UPDATE tblFilledForms SET Text1 = '" + \''; DROP yourTable;-- + ' etc. 

,然後:

UPDATE tblFilledForms SET Text1 = '\''; DROP yourTable;-- ' etc. 

'\'」被作爲一個單引號的文本字符串,如果你的數據庫支持轉義字符 - 賓果你的妥協。

同樣,保護必須記住是有效的,即使提供的示例更新語句也未能保護where子句中的參數,是因爲DGVNotes.SelectedRows(0).Cells(「FilledFormID」)。Value。 ToString)永遠不會被用戶輸入?這將適用於應用程序的整個生命週期?

+0

大概只是我使用的數據庫技術...... MS SQL Server認爲「意味着你實際上想輸入」它不是字面或轉義字符。對於SQL Server,兩個單引號一起被解釋爲一個字面單引號,在字符串內將任何''傳入字符串'並且它不會被執行。 – Jrud 2009-12-02 22:35:56

+0

是的,SQL只能逃脫某些事情並使用[作爲轉義,MySQL使用\我相信這會遇到這個問題。 – Andrew 2009-12-02 22:56:01