防止SQL注入的注意事項

2021-05-22 06:10:35 字數 3463 閱讀 7718

防止sql注入攻擊的注意事項

一. sql injection及其防範的基本知識

可能大家都知道,sql注入主要是利用字元型引數輸入的檢查漏洞。

比如說,程式中有這樣的查詢:

string sql = "select * from siteusers where username='" + username + "'";

其中的username引數是從使用者介面上輸入的。

如果是正常的輸入,比如「peter」,sql語句會串接成:

"select * from siteusers where username='peter'";

如果攻擊者輸入的是下面的字串:

"***'; drop table siteusers where 1=1 or username='***"

此時sql語句會變成下面這個樣子:

"select * from siteusers where username='***'; drop table siteusers where 1=1 or username='***'";

其結果,得到執行的是兩個sql語句,第二個語句的後果就比較嚴重了。

防止注入的方法其實很簡單,只要把使用者輸入的單引號變成雙份就行了:

string sql = "select * from siteusers where username='" + username.replace("'","''") + "'";

這樣,如果輸入的是上面那種惡意引數,整個sql語句會變成:

"select * from siteusers where username='***''; drop table siteusers where 1=1 or username=''***'";

被執行的還是乙個sql語句,整個粗體部分都成為引數值。

一般的做法,是在程式中統一呼叫下面這樣的共通函式,對引數進行處理:

private string safesqlliteral(string inputsql)

由於很多人會疏忽這種單引號替換,所以真正安全的做法是使用引數化查詢。

二. 引數化查詢

在ado.net中,提供了一種引數化查詢方法,可以替代上面這種拼接sql語句的做法。

引數化查詢的具體實現是:

(1)組織乙個夾帶引數名的sql語句,作為sqlcommand的commandtext。

(2)使用parameters.add方法設定引數值。

(3)執行sqlcommand。(這個步驟跟上面那種拼接sql的辦法是一樣的。)

下面是乙個例子:

string sql = "select t2.dep_code, t2.dep_name from dep ";

sql += " where t2.dep_name like ('%'+@param+ '%') ";

sqlcommand sqlcommand = new sqlcommand(sql,cn);

sqlcommand.parameters.add(new sqlparameter("param",s);

其中的@param就是引數名,s則是使用者輸入的查詢條件字串。

(順便注:oracle查詢語句引數用問號表示,不是「@引數名」的形式。)

使用這種引數化查詢的辦法,防止sql注入的任務就交給ado.net了。

如果在專案中統一規定必須使用引數化查詢,就不用擔心因個別程式設計師的疏忽導致的sql注入漏洞了。

但是,問題還沒有完,sql注入的漏洞是堵住了,但是查詢結果的正確性,引數化查詢並不能幫上什麼忙。

三. 萬用字元問題

如果使用like語句進行模糊查詢,會有一些特殊的萬用字元問題。

sql server的萬用字元包括下劃線(_)和百分號(%),分別表示單個字元和任意多字元。

如果使用者輸入引數中包括這些萬用字元,就會出現結果不正確的問題。

比如說:

where t2.name like ('%'+ @param + '%')

如果使用者輸入下劃線,他期待的結果應該是name字段值含有下劃線的記錄,但是結果是所有記錄都會被查詢出來。輸入百分號也是如此。

為此,在將使用者輸入的內容作為引數值傳入之前,必須進行萬用字元的轉義處理(英文叫做escape),也就是說,如果使用者輸入的查詢條件中含有萬用字元,必須將這些字元作為資料而不是萬用字元來對待。

在sql server的查詢語句中,將萬用字元轉義為普通資料的方法是用方括號括起來。

比如說,如果想要查詢帶有下劃線的字段,正確的寫法是:

where t2.name like ('%'+ '[_]' + '%')

同樣,如果想要查詢帶有百分號的字段,正確的寫法是:

where t2.name like ('%'+ '[%]' + '%')

所以,即使使用引數化查詢,也必須在將使用者輸入的內容當作引數值傳入sqlcommand.parameters之前,先進行下面的處理:

s = s.replace("%", "[%]");

s = s.replace("_", "[_]");

四. 方括號問題

如果你足夠細心,可能發現了還有乙個方括號問題。

既然方括號是用來界定資料內容的,那麼如果使用者輸入的查詢引數本身就包括方括號時,會出現什麼結果呢?

根據使用者的期望,如果輸入乙個方括號,查詢結果中應該只包括那些字段值中含有方括號的記錄。

但是實驗結果表明,如果是沒有配成對的單個左方括號,查詢時這個左方括號會被忽略。

也就是說,下面這個語句: where t2.name like ('%'+ '[' + '%')

等價於下面這個語句:

where t2.name like ('%'+ '' + '%')

這將導致查詢結果中包含表中的全部記錄,就像沒有任何過濾條件一樣。

為此,如果使用者輸入的查詢條件中含有左方括號的話,還必須對左方括號進行轉義:

s = s.replace("[", "[");

注:右方括號沒有這個問題。

五. 其他注意事項

按照微軟的建議,凡是有可能導致問題的輸入,可以在ui部分就進行檢查並拒掉。

這些可疑輸入包括:

分號(;):多個查詢語句之間的分隔符,注入攻擊時的惡意查詢語句往往就是第二個查詢語句。

單引號('):字串資料分隔符,這是最危險的,前面已經討論了。

注釋符(--或者/*,*/):有些資料庫可以利用注釋設定一些查詢引擎的行為,比如如何利用索引等。

xp_:擴充套件儲存過程的字首,sql注入攻擊得手之後,攻擊者往往會通過執行xp_cmdshell之類的擴充套件儲存過程,獲取系統資訊,甚至控制、破壞系統。

六、結論

為了防止sql注入,同時避免使用者輸入特殊字元時查詢結果不準確的問題,應該做兩件事:

(1)使用引數化查詢。

(2)在使用使用者輸入的字串資料設定查詢引數值之前,首先呼叫下面的共通處理函式:

private static string convertsql(string sql)

SQL 注意事項

選擇表名 配置ctrl 3 能夠select 桌 use nb go 物 storedprocedure dbo sp select 指令碼日期 05 28 2015 21 46 25 set ansi nulls on go set quoted identifier on go create p...

sql 注意事項

在 oracle 都是不等於號的意思。都可以使用。但是奇怪的是,我想拿出price 不是180000旳商品時 select id,name,from product where price 180000 執行這個語句是,price null 的記錄不出來,也就是拿不到price 是null的商品,必...

伺服器防sql注入注意事項

1 前端所有的輸入內容都需要進行特殊 過濾,過濾方法有很多,可以是js也可以是後端來操作並過濾字元。如果是常見的登入註冊這種的話,建議使用正則匹配的方式限制輸入內容。2 富文字編輯器漏洞,如果是在前端需要編輯器的地方,請關閉附件上傳,輸入內容進行過濾,需要檔案上傳的地方可以在後端使用 驗證。有些黑客...