asp.net 預(yù)防SQL注入攻擊之我見(jiàn)
更新時(shí)間:2009年11月26日 19:07:12 作者:
說(shuō)起防止SQL注入攻擊,感覺(jué)很郁悶,這么多年了大家一直在討論,也一直在爭(zhēng)論,可是到了現(xiàn)在似乎還是沒(méi)有定論。當(dāng)不知道注入原理的時(shí)候會(huì)覺(jué)得很神奇,怎么就被注入了呢?會(huì)覺(jué)得很難預(yù)防。但是當(dāng)知道了注入原理之后預(yù)防不就是很簡(jiǎn)單的事情了嗎?
1、 SQL注入攻擊的本質(zhì):讓客戶端傳遞過(guò)去的字符串變成SQL語(yǔ)句,而且能夠被執(zhí)行。
2、 每個(gè)程序員都必須肩負(fù)起防止SQL注入攻擊的責(zé)任。
說(shuō)起防止SQL注入攻擊,感覺(jué)很郁悶,這么多年了大家一直在討論,也一直在爭(zhēng)論,可是到了現(xiàn)在似乎還是沒(méi)有定論。當(dāng)不知道注入原理的時(shí)候會(huì)覺(jué)得很神奇,怎么就被注入了呢?會(huì)覺(jué)得很難預(yù)防。但是當(dāng)知道了注入原理之后預(yù)防不就是很簡(jiǎn)單的事情了嗎?
第一次聽(tīng)說(shuō)SQL注入攻擊的時(shí)候還是在2004年(好像得知的比較晚),那是還是在寫(xiě)asp呢。在一次寫(xiě)代碼的時(shí)候,有同事問(wèn)我,你的這段代碼防注入攻擊了嗎?什么攻擊?這是什么呀。
后來(lái)到網(wǎng)上各種找,終于弄明白了是怎么攻擊進(jìn)來(lái)的了。注入攻擊都是來(lái)自于客戶端,無(wú)論是表單提交、URL傳值還是Cookie等,其實(shí)原理都是一樣的。到了服務(wù)器端可以分成三種情況:數(shù)字、日期時(shí)間、字符串。
一、數(shù)字。
如何注入?
假設(shè)我們要實(shí)現(xiàn)一個(gè)顯示新聞的頁(yè)面,我們可能會(huì)隨手寫(xiě)下下面的代碼:
string id = Request.QueryString["id"];
string sql = "select * from news where ColID=" + id;
如果傳遞過(guò)來(lái)的 id是我們想像的 數(shù)字(比如168),那么自然不會(huì)有什么問(wèn)題。但是如果傳遞過(guò)來(lái)的id是“168 delete from table ”的話,那么sql的值就變成了“select * from table where ColID=168 delete from news”。對(duì)于SQL Server來(lái)說(shuō)是支持一次提交多條SQL語(yǔ)句的,這個(gè)為我們提供了方便之余也為SQL注入敞開(kāi)了大門(mén)。顯然如果這條SQL語(yǔ)句被執(zhí)行的話,那么news表里的記錄就都沒(méi)有了。
那么如何預(yù)防呢?很簡(jiǎn)單,因?yàn)镃olID字段的類型是int的,那么我們只需要驗(yàn)證一下傳遞過(guò)來(lái)的id是不是整數(shù)就可以了。是整數(shù)就不存在注入;如果不是那么就有可能存在注入。即使不存在注入,把一個(gè)不是整數(shù)的id拼接進(jìn)去也會(huì)造成執(zhí)行錯(cuò)誤。
所以說(shuō)不管是不是為了預(yù)防SQL注入,也都應(yīng)該驗(yàn)證id是不是整數(shù)?! ?
驗(yàn)證方法嘛,可以用TryParse,可以用正則,也可以自己寫(xiě)函數(shù)驗(yàn)證。但是不建議用try異常的方式,因?yàn)檫@個(gè)有效率問(wèn)題。
這里還有一個(gè)特殊情況,就是對(duì)于批量刪除這類的會(huì)傳遞過(guò)來(lái)多個(gè)數(shù)字,比如“1,2,3,10”,這個(gè)也需要驗(yàn)證一下,萬(wàn)一有人利用這個(gè)漏洞呢。至于驗(yàn)證方法也很簡(jiǎn)單,自己寫(xiě)個(gè)函數(shù)就ok了。
二、日期時(shí)間
這個(gè)和數(shù)字的情況是一樣的,驗(yàn)證是不是日期時(shí)間即可。
三、字符串
最麻煩、爭(zhēng)議最大的就是這個(gè)了。
先看一下如何注入
比如我們先要按照新聞標(biāo)題來(lái)進(jìn)行查詢,可能寫(xiě)的代碼:
string key = txtTitle.Text;
string sql = "select * from news where title like '%" + key + "%'";
這個(gè)又是如何注入的呢?我想先問(wèn)大家一個(gè)問(wèn)題:如果key的值永遠(yuǎn)都不會(huì)包含單引號(hào),那么會(huì)不會(huì)被注入進(jìn)來(lái)?
那么用了單引號(hào)又是如何注入的呢?假設(shè)key=" ' delete from news --" ,那么sql的值就是“ select * from news where title like '%' delete from news -- ' ”。
先用一個(gè)單引號(hào)和前面的單引號(hào)組成一對(duì)封閉的單引號(hào),這一對(duì)單引號(hào)內(nèi)部('%')就作為字符串處理,而外面的就被作為SQL語(yǔ)句處理,而第二個(gè)單引號(hào)被 “--”給注釋掉了,這樣就保證了整個(gè)sql語(yǔ)句的正確性。
這是注入的一種方法。
那么如何來(lái)防止呢?想想剛才的問(wèn)題,如果沒(méi)有單引號(hào)是不是就天下太平了呢?對(duì)于這種情況(前面的“數(shù)字”的情況不算),到目前為止我是沒(méi)發(fā)現(xiàn)不用單引號(hào),還能夠注入進(jìn)來(lái)的方法。也許是我孤陋寡聞吧,不知道各位高手是否知道對(duì)于這種情況,不用單引號(hào)還能注入進(jìn)來(lái)的方法。
既然找到了罪魁禍?zhǔn)?,那么就好辦了,把單引號(hào)干掉就ok了。key = key.Replace("'", "''");這時(shí)候sql的值就是” select * from news where title like '%'' delete from news --'”。
對(duì)于SQL 來(lái)說(shuō)在一對(duì)單引號(hào)內(nèi)部的兩個(gè)單引號(hào)表示一個(gè)字符串形式的單引號(hào)。這樣我們就把罪魁禍?zhǔn)赘脑斐闪俗址恕T谝粚?duì)單引號(hào)內(nèi)的“--”也是普通的字符串而不代表注釋。
罪魁禍?zhǔn)资菃我?hào),想不明白為什么有許多人都去過(guò)濾 “delete、update”這一類的關(guān)鍵字,他們都是安善良民呀,他們是很冤枉的。當(dāng)然了,如果前提是程序都已經(jīng)寫(xiě)好了,不能修改內(nèi)部代碼,那就另當(dāng)別論了。至于“--”頂多算是幫兇,如果您不放心的話,把他處理了也行。
總結(jié):數(shù)字、日期時(shí)間的,驗(yàn)證類型;字符串的,處理好單引號(hào)。
另外為了安全起見(jiàn),不要用sa連接數(shù)據(jù)庫(kù),xp_cmdshell這一類的有危險(xiǎn)的擴(kuò)展存儲(chǔ)過(guò)程也應(yīng)該處理一下(比如刪除)。
ps:添加修改數(shù)據(jù)的時(shí)候可以用參數(shù)化的SQL語(yǔ)句,但是目的不是防止注入,而是重用執(zhí)行計(jì)劃。
還有就是js腳本的問(wèn)題,這個(gè)還沒(méi)有仔細(xì)考慮,可以用html編碼的方式,也可以用替換的方式,還有ubb的漏洞等。
2、 每個(gè)程序員都必須肩負(fù)起防止SQL注入攻擊的責(zé)任。
說(shuō)起防止SQL注入攻擊,感覺(jué)很郁悶,這么多年了大家一直在討論,也一直在爭(zhēng)論,可是到了現(xiàn)在似乎還是沒(méi)有定論。當(dāng)不知道注入原理的時(shí)候會(huì)覺(jué)得很神奇,怎么就被注入了呢?會(huì)覺(jué)得很難預(yù)防。但是當(dāng)知道了注入原理之后預(yù)防不就是很簡(jiǎn)單的事情了嗎?
第一次聽(tīng)說(shuō)SQL注入攻擊的時(shí)候還是在2004年(好像得知的比較晚),那是還是在寫(xiě)asp呢。在一次寫(xiě)代碼的時(shí)候,有同事問(wèn)我,你的這段代碼防注入攻擊了嗎?什么攻擊?這是什么呀。
后來(lái)到網(wǎng)上各種找,終于弄明白了是怎么攻擊進(jìn)來(lái)的了。注入攻擊都是來(lái)自于客戶端,無(wú)論是表單提交、URL傳值還是Cookie等,其實(shí)原理都是一樣的。到了服務(wù)器端可以分成三種情況:數(shù)字、日期時(shí)間、字符串。
一、數(shù)字。
如何注入?
假設(shè)我們要實(shí)現(xiàn)一個(gè)顯示新聞的頁(yè)面,我們可能會(huì)隨手寫(xiě)下下面的代碼:
復(fù)制代碼 代碼如下:
string id = Request.QueryString["id"];
string sql = "select * from news where ColID=" + id;
如果傳遞過(guò)來(lái)的 id是我們想像的 數(shù)字(比如168),那么自然不會(huì)有什么問(wèn)題。但是如果傳遞過(guò)來(lái)的id是“168 delete from table ”的話,那么sql的值就變成了“select * from table where ColID=168 delete from news”。對(duì)于SQL Server來(lái)說(shuō)是支持一次提交多條SQL語(yǔ)句的,這個(gè)為我們提供了方便之余也為SQL注入敞開(kāi)了大門(mén)。顯然如果這條SQL語(yǔ)句被執(zhí)行的話,那么news表里的記錄就都沒(méi)有了。
那么如何預(yù)防呢?很簡(jiǎn)單,因?yàn)镃olID字段的類型是int的,那么我們只需要驗(yàn)證一下傳遞過(guò)來(lái)的id是不是整數(shù)就可以了。是整數(shù)就不存在注入;如果不是那么就有可能存在注入。即使不存在注入,把一個(gè)不是整數(shù)的id拼接進(jìn)去也會(huì)造成執(zhí)行錯(cuò)誤。
所以說(shuō)不管是不是為了預(yù)防SQL注入,也都應(yīng)該驗(yàn)證id是不是整數(shù)?! ?
驗(yàn)證方法嘛,可以用TryParse,可以用正則,也可以自己寫(xiě)函數(shù)驗(yàn)證。但是不建議用try異常的方式,因?yàn)檫@個(gè)有效率問(wèn)題。
這里還有一個(gè)特殊情況,就是對(duì)于批量刪除這類的會(huì)傳遞過(guò)來(lái)多個(gè)數(shù)字,比如“1,2,3,10”,這個(gè)也需要驗(yàn)證一下,萬(wàn)一有人利用這個(gè)漏洞呢。至于驗(yàn)證方法也很簡(jiǎn)單,自己寫(xiě)個(gè)函數(shù)就ok了。
二、日期時(shí)間
這個(gè)和數(shù)字的情況是一樣的,驗(yàn)證是不是日期時(shí)間即可。
三、字符串
最麻煩、爭(zhēng)議最大的就是這個(gè)了。
先看一下如何注入
比如我們先要按照新聞標(biāo)題來(lái)進(jìn)行查詢,可能寫(xiě)的代碼:
復(fù)制代碼 代碼如下:
string key = txtTitle.Text;
string sql = "select * from news where title like '%" + key + "%'";
這個(gè)又是如何注入的呢?我想先問(wèn)大家一個(gè)問(wèn)題:如果key的值永遠(yuǎn)都不會(huì)包含單引號(hào),那么會(huì)不會(huì)被注入進(jìn)來(lái)?
那么用了單引號(hào)又是如何注入的呢?假設(shè)key=" ' delete from news --" ,那么sql的值就是“ select * from news where title like '%' delete from news -- ' ”。
先用一個(gè)單引號(hào)和前面的單引號(hào)組成一對(duì)封閉的單引號(hào),這一對(duì)單引號(hào)內(nèi)部('%')就作為字符串處理,而外面的就被作為SQL語(yǔ)句處理,而第二個(gè)單引號(hào)被 “--”給注釋掉了,這樣就保證了整個(gè)sql語(yǔ)句的正確性。
這是注入的一種方法。
那么如何來(lái)防止呢?想想剛才的問(wèn)題,如果沒(méi)有單引號(hào)是不是就天下太平了呢?對(duì)于這種情況(前面的“數(shù)字”的情況不算),到目前為止我是沒(méi)發(fā)現(xiàn)不用單引號(hào),還能夠注入進(jìn)來(lái)的方法。也許是我孤陋寡聞吧,不知道各位高手是否知道對(duì)于這種情況,不用單引號(hào)還能注入進(jìn)來(lái)的方法。
既然找到了罪魁禍?zhǔn)?,那么就好辦了,把單引號(hào)干掉就ok了。key = key.Replace("'", "''");這時(shí)候sql的值就是” select * from news where title like '%'' delete from news --'”。
對(duì)于SQL 來(lái)說(shuō)在一對(duì)單引號(hào)內(nèi)部的兩個(gè)單引號(hào)表示一個(gè)字符串形式的單引號(hào)。這樣我們就把罪魁禍?zhǔn)赘脑斐闪俗址恕T谝粚?duì)單引號(hào)內(nèi)的“--”也是普通的字符串而不代表注釋。
罪魁禍?zhǔn)资菃我?hào),想不明白為什么有許多人都去過(guò)濾 “delete、update”這一類的關(guān)鍵字,他們都是安善良民呀,他們是很冤枉的。當(dāng)然了,如果前提是程序都已經(jīng)寫(xiě)好了,不能修改內(nèi)部代碼,那就另當(dāng)別論了。至于“--”頂多算是幫兇,如果您不放心的話,把他處理了也行。
總結(jié):數(shù)字、日期時(shí)間的,驗(yàn)證類型;字符串的,處理好單引號(hào)。
另外為了安全起見(jiàn),不要用sa連接數(shù)據(jù)庫(kù),xp_cmdshell這一類的有危險(xiǎn)的擴(kuò)展存儲(chǔ)過(guò)程也應(yīng)該處理一下(比如刪除)。
ps:添加修改數(shù)據(jù)的時(shí)候可以用參數(shù)化的SQL語(yǔ)句,但是目的不是防止注入,而是重用執(zhí)行計(jì)劃。
還有就是js腳本的問(wèn)題,這個(gè)還沒(méi)有仔細(xì)考慮,可以用html編碼的方式,也可以用替換的方式,還有ubb的漏洞等。
相關(guān)文章
C#開(kāi)發(fā)微信 二維碼鼠標(biāo)滑動(dòng) 圖像顯示隱藏效果(推薦)
客戶端微信在二維碼狀態(tài)下,鼠標(biāo)滑過(guò),會(huì)有一張手機(jī)的圖片滑動(dòng)滑出,從隱藏到顯示,從顯示到隱藏。效果非常棒,本文思路介紹明確,感興趣的朋友一起看看吧2016-11-11ASP.NET使用My97DatePicker日期控件實(shí)例
這篇文章主要為大家詳細(xì)介紹了ASP.NET使用My97DatePicker日期控件實(shí)例,如何使用My97DatePicker日期控件,本文為大家介紹,感興趣的小伙伴們可以參考一下2016-04-04FileUpload1 上傳文件類型驗(yàn)證正則表達(dá)式
FileUpload1 上傳文件類型驗(yàn)證正則表達(dá)式...2006-10-10asp.net不同頁(yè)面間數(shù)據(jù)傳遞的多種方法
這篇文章主要介紹了asp.net不同頁(yè)面間數(shù)據(jù)傳遞的多種方法,包括使用QueryString顯式傳遞、頁(yè)面對(duì)象的屬性、cookie、Cache等9種方法2014-01-01解決 The Controls collection cannot be modified because the co
在.aspx或.ascx的如果包括%,并在.aspx, .ascs中使用了AjaxToolkit中的控件,那么很可能會(huì)引發(fā)這個(gè)問(wèn)題,下面給出具體的解決方法。2010-10-10Asp.Net Core輕量級(jí)Aop解決方案:AspectCore
這篇文章主要介紹了Asp.Net Core輕量級(jí)Aop解決方案:AspectCore,需要的朋友可以參考下2017-06-06如何使用.NET Core 選項(xiàng)模式【Options】
這篇文章主要介紹了如何使用.NET Core 選項(xiàng)模式,文中講解非常詳細(xì),代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07