如何防止SQL注入

責(zé)任編輯:sjia

2012-11-09 08:48:52

摘自:IT168

跨站腳本攻擊最大的魅力是通過(guò)HTML注入劫持用戶的瀏覽器,任意構(gòu)造用戶當(dāng)前瀏覽的HTML內(nèi)容,甚至可以模擬用戶當(dāng)前的操作。

當(dāng)你打開(kāi)百度新聞搜索“黑客”關(guān)鍵字時(shí)能看到什么?沒(méi)錯(cuò),有太多知名的網(wǎng)站被黑客攻破,有太多牛X的IT系統(tǒng)對(duì)黑客來(lái)說(shuō)如入無(wú)人之境……

進(jìn)入WEB2.0時(shí)代,我們的IT當(dāng)真變得如此脆弱了嗎?記得在一次有關(guān)安全的研討會(huì)上,有專(zhuān)家談到了這樣的觀點(diǎn):互聯(lián)網(wǎng)在設(shè)計(jì)之初,也沒(méi)能預(yù)想到互聯(lián)網(wǎng)會(huì)發(fā)展成現(xiàn)在的龐大規(guī)模,如果互聯(lián)網(wǎng)依然只應(yīng)用于教育網(wǎng)、科研網(wǎng),就不會(huì)有這么多的問(wèn)題,難道我們真得需要在重新織一張網(wǎng)?雖然這只是一種假設(shè),也可能是未來(lái)創(chuàng)新的一個(gè)星星之火,但在現(xiàn)階段,還是讓我們收回思想的翅膀,來(lái)解決實(shí)際中的問(wèn)題吧!

網(wǎng)站安全在經(jīng)歷了2011年底的泄密門(mén)之后,得到了各方面的重視,互聯(lián)網(wǎng)企業(yè)開(kāi)始重新審視自身的安全性、安全廠商開(kāi)始更多的關(guān)注這方面的問(wèn)題并推出了相應(yīng)的解決方案、政府也在從法律法規(guī)方面對(duì)網(wǎng)站安全進(jìn)行了相關(guān)的規(guī)定(未證實(shí)消息:中國(guó)的薩班斯法案在今年也將出臺(tái))。

近日,小編從國(guó)內(nèi)知名的漏洞報(bào)告平臺(tái)WooYun.org上得到了以下幾張圖,圖中標(biāo)注的是各企業(yè)網(wǎng)站所存在的漏洞類(lèi)型和造成系統(tǒng)漏洞的主要原因:

網(wǎng)站安全實(shí)踐:對(duì)預(yù)防SQL注入的幾點(diǎn)建議

從上圖我們可以不難找出企業(yè)網(wǎng)站存在安全風(fēng)險(xiǎn)的幾個(gè)同共點(diǎn):XSS跨站腳本攻擊、SQL注入漏洞、后臺(tái)弱口令、系統(tǒng)/服務(wù)運(yùn)維配置不當(dāng)以及系統(tǒng)/服務(wù)補(bǔ)丁不及時(shí)……下面我們就從這主要的幾點(diǎn)開(kāi)始和大家一起探討:

1、 XSS跨站腳本攻擊

上圖所列出的互聯(lián)網(wǎng)企業(yè)有門(mén)戶網(wǎng)站、行業(yè)網(wǎng)站、視頻網(wǎng)站、旅游網(wǎng)站等,從不同類(lèi)型的網(wǎng)站我們可以看出,XSS跨站腳本攻擊是黑客使用最普遍的攻擊方式,這里我們?yōu)榇蠹艺砹薠SS跨站腳本攻擊的原理,希望能對(duì)大家有幫助。

小白一下:XSS又叫CSS (Cross Site Script) ,跨站腳本攻擊。它指的是惡意攻擊者往Web頁(yè)面里插入惡意html代碼,當(dāng)用戶瀏覽該頁(yè)之時(shí),嵌入其中Web里面的html代碼會(huì)被執(zhí)行,從而達(dá)到惡意用戶的特殊目的。XSS屬于被動(dòng)式的攻擊,因?yàn)槠浔粍?dòng)且不好利用,所以許多人常呼略其危害性。

跨站腳本攻擊最大的魅力是通過(guò)HTML注入劫持用戶的瀏覽器,任意構(gòu)造用戶當(dāng)前瀏覽的HTML內(nèi)容,甚至可以模擬用戶當(dāng)前的操作。這里介紹一種新式攻擊方法:XSS Phishing(跨站腳本釣魚(yú)攻擊),利用這種方式可以直接盜取用戶的密碼,下面我就拿最近PHPWIND論壇所暴出的XSS做一下演示,PHPWIND對(duì)上傳文件名沒(méi)有處理嚴(yán)格,導(dǎo)致可以寫(xiě)入跨站腳本。

先做一個(gè)簡(jiǎn)單的測(cè)試,發(fā)一篇新帖,在附件中隨意寫(xiě)入一個(gè)本地路徑加帶“<” 和“>”的文件名,如圖一

發(fā)帖成功后我們會(huì)發(fā)現(xiàn),帖子附件名已經(jīng)沒(méi)有了,如圖二

網(wǎng)站安全實(shí)踐:對(duì)預(yù)防SQL注入的幾點(diǎn)建議

我們查看當(dāng)前頁(yè)面的源代碼會(huì)發(fā)現(xiàn)已經(jīng)寫(xiě)到頁(yè)面內(nèi),如圖三

當(dāng)然要寫(xiě)入腳本,PHPWIND還是做了限制,文件名中出現(xiàn)"(","/"字符將會(huì)被過(guò)濾,不過(guò)可以利用HTML轉(zhuǎn)碼的方式繞過(guò)這個(gè)限制,如轉(zhuǎn)換成

>

這樣我們已經(jīng)實(shí)現(xiàn)了跨站腳本的寫(xiě)入,關(guān)鍵是怎么實(shí)現(xiàn)攻擊,這一處跨站腳本漏洞進(jìn)行了HTML轉(zhuǎn)碼,我們不方便寫(xiě)入過(guò)長(zhǎng)的內(nèi)容,那么就加載一個(gè)JS文件,動(dòng)態(tài)創(chuàng)建一個(gè)script標(biāo)記,代碼如下:

>

OK,到了這一步我們就可以在JS中任意構(gòu)造我們的攻擊代碼,攻擊的思路是當(dāng)用戶訪問(wèn)帖子,利用腳本清空當(dāng)前頁(yè)面,然后重新寫(xiě)成釣魚(yú)頁(yè)面。

首先我們可以實(shí)驗(yàn)一下,javacript有一個(gè)小特性,延時(shí)輸出將會(huì)清空當(dāng)前頁(yè)面所有的內(nèi)容,代碼如下:

function Phish(){

info = "我是來(lái)釣魚(yú)的!"

document.write(info);

}

function doit(){

setTimeout("Phish()", 1000 );

}doit()

如圖四,帖子頁(yè)面的代碼和內(nèi)容全變成了“我是來(lái)釣魚(yú)的!”

網(wǎng)站安全實(shí)踐:對(duì)預(yù)防SQL注入的幾點(diǎn)建議

想一想,如果我們把info變量的內(nèi)容變成HTML代碼會(huì)怎樣,如圖五

網(wǎng)站安全實(shí)踐:對(duì)預(yù)防SQL注入的幾點(diǎn)建議

嘿嘿,邪惡一點(diǎn)!我們完全可以把頁(yè)面變成一個(gè)自己操縱的登錄頁(yè)面,將表單的值指向遠(yuǎn)程服務(wù)器上的程序,如圖六

網(wǎng)站安全實(shí)踐:對(duì)預(yù)防SQL注入的幾點(diǎn)建議

然后遠(yuǎn)程服務(wù)器上的程序?qū)⒔邮鼙韱蜳OST的用戶和密碼,當(dāng)然我們可以做巧妙點(diǎn),讓其訪問(wèn)后又轉(zhuǎn)跳回論壇首頁(yè),代碼如下:

網(wǎng)站安全實(shí)踐:對(duì)預(yù)防SQL注入的幾點(diǎn)建議

最后我們便完成了釣魚(yú)的過(guò)程,管理員訪問(wèn)我們的帖子,馬上重寫(xiě)當(dāng)前頁(yè)面,設(shè)置一個(gè)重新登錄的陷阱,盜取用戶名和密碼,全部過(guò)程只在沒(méi)有察覺(jué)的一瞬間.

這類(lèi)攻擊方式危害很大,文中的原始代碼只是描敘一下思路,有很多破綻,當(dāng)然如果你夠邪惡的話,完全可以自己重寫(xiě)代碼,釣魚(yú)于無(wú)形之中。

提醒一下,跨站腳本不僅僅是簡(jiǎn)單的掛馬,XSS Phishing(跨站腳本釣魚(yú)攻擊)只是一個(gè)簡(jiǎn)單的開(kāi)始!

2、 SQL注入漏洞

SQL注入漏洞的產(chǎn)生原因是網(wǎng)站程序在編寫(xiě)時(shí),沒(méi)有對(duì)用戶輸入數(shù)據(jù)的合法性進(jìn)行判斷,導(dǎo)致應(yīng)用程序存在安全隱患。SQL注入漏洞攻擊的就是利用現(xiàn)有應(yīng)用程序沒(méi)有對(duì)用戶輸入數(shù)據(jù)的合法性進(jìn)行判斷,將惡意的SQL命令注入到后臺(tái)數(shù)據(jù)庫(kù)引擎執(zhí)行的黑客攻擊手段。

下面總結(jié)了一位開(kāi)發(fā)者對(duì)預(yù)防SQL注入的幾點(diǎn)建議:

開(kāi)發(fā)者的觀點(diǎn):SQL注入攻擊的本質(zhì)是讓客戶端傳遞過(guò)去的字符串變成SQL語(yǔ)句,而且能夠被執(zhí)行;每個(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í)間、字符串。

(1)、數(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字段的類(lèi)型是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ì)于批量刪除這類(lèi)的會(huì)傳遞過(guò)來(lái)多個(gè)數(shù)字,比如“1,2,3,10”,這個(gè)也需要驗(yàn)證一下,萬(wàn)一有人利用這個(gè)漏洞呢。至于驗(yàn)證方法也很簡(jiǎn)單,自己寫(xiě)個(gè)函數(shù)就ok了。

(2)、日期時(shí)間

這個(gè)和數(shù)字的情況是一樣的,驗(yàn)證是不是日期時(shí)間即可。

(3)、字符串

最麻煩、爭(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)赘脑斐闪俗址?。在一?duì)單引號(hào)內(nèi)的“--”也是普通的字符串而不代表注釋。

罪魁禍?zhǔn)资菃我?hào),想不明白為什么有許多人都去過(guò)濾 “delete、update”這一類(lèi)的關(guān)鍵字,他們都是安善良民呀,他們是很冤枉的。當(dāng)然了,如果前提是程序都已經(jīng)寫(xiě)好了,不能修改內(nèi)部代碼,那就另當(dāng)別論了。至于“--”頂多算是幫兇,如果您不放心的話,把他處理了也行。

總結(jié):數(shù)字、日期時(shí)間的,驗(yàn)證類(lèi)型;字符串的,處理好單引號(hào)。另外為了安全起見(jiàn),不要用sa連接數(shù)據(jù)庫(kù),xp_cmdshell這一類(lèi)的有危險(xiǎn)的擴(kuò)展存儲(chǔ)過(guò)程也應(yīng)該處理一下(比如刪除)。

3、其他需要關(guān)注的……

從第一頁(yè)給出的那張圖中,大家也許能看出些不同。沒(méi)錯(cuò),有的互聯(lián)網(wǎng)企業(yè)在系統(tǒng)/服務(wù)運(yùn)維方面做的非常好,比如門(mén)戶網(wǎng)站的百度、騰訊;也有的互聯(lián)網(wǎng)企業(yè)在系統(tǒng)/服務(wù)運(yùn)維上就差勁了許多。關(guān)于系統(tǒng)運(yùn)維,各位都是大牛,小編就不在這里班門(mén)弄斧了。

鏈接已復(fù)制,快去分享吧

企業(yè)網(wǎng)版權(quán)所有?2010-2024 京ICP備09108050號(hào)-6京公網(wǎng)安備 11010502049343號(hào)