防止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 富文字編輯器漏洞,如果是在前端需要編輯器的地方,請關閉附件上傳,輸入內容進行過濾,需要檔案上傳的地方可以在後端使用 驗證。有些黑客...