小心你的WEB應(yīng)用程序成為數(shù)據(jù)竊賊的幫兇
當(dāng)心,你以為固若金湯的數(shù)據(jù)庫(kù)可能已遭到了入侵。你需要重新思考一下自己公司的網(wǎng)站是否真得不會(huì)遭到SQL注入攻擊。SQL注入是最流行也是最危險(xiǎn)的Web應(yīng)用程序漏洞利用技術(shù),它可以攻擊存儲(chǔ)著珍貴企業(yè)信息的后端數(shù)據(jù)庫(kù),且“簡(jiǎn)約高效”。
本文將闡述攻擊者如何通過(guò)這種方法來(lái)利用Web應(yīng)用程序的漏洞。有時(shí),即使攻擊者也不了解自己正在利用的漏洞的性質(zhì)。
何為SQL注入
就其最基本的意義來(lái)說(shuō),SQL注入只不過(guò)是操縱一個(gè)已有的SQL查詢,執(zhí)行一個(gè)并非開(kāi)發(fā)人員意圖的動(dòng)作。這種動(dòng)作通常是通過(guò)Web應(yīng)用程序的用戶界面完成的。
但這種攻擊是如何進(jìn)行的?它為什么屢屢得逞?
Web應(yīng)用程序和數(shù)據(jù)庫(kù)之間的正常交互
所有的SQL注入漏洞都是由某些未經(jīng)驗(yàn)證的用戶輸入開(kāi)始的。用戶輸入可以采取多種形式,它可以包括一個(gè)攻擊者操縱的由服務(wù)器處理的任何東西,例如:用戶代理、HTTP報(bào)頭、POST參數(shù)、cookies、GET參數(shù),甚至網(wǎng)址標(biāo)頭等。是什么令未經(jīng)驗(yàn)證的用戶輸入如此特殊呢?答案是:應(yīng)用程序并沒(méi)有對(duì)其進(jìn)行充分的檢查,從而不能確保所收到的輸入就是所期望的類型和方式。例如,雖然你的應(yīng)用程序的編制目的是為了接收可以包括字母、數(shù)字的字符串作為用戶名,但此程序并沒(méi)有驗(yàn)證輸入,從而使得黑客可以插入SQL注入的數(shù)據(jù)庫(kù)查詢:
比如,一個(gè)典型的網(wǎng)站會(huì)要求你的用戶名,并希望這個(gè)結(jié)果是“Zhangsan”:
Wangzhan.com/usertetail.asp?username=Zhangsan
在這個(gè)例子中,有可能會(huì)發(fā)生這樣的情況:某個(gè)查詢促使網(wǎng)站在后臺(tái)與數(shù)據(jù)庫(kù)交互,從而獲取關(guān)于用戶(如,Zhangsan)的信息:
SELECT uname,fname,lname,phone,street,city,state,zip FROM users WHERE user =$var_username
當(dāng)Web應(yīng)用程序代碼處理這個(gè)請(qǐng)求時(shí),為了完成查詢,來(lái)自用戶名的值(Zhangsan)被傳遞給$var_username。服務(wù)器應(yīng)當(dāng)將SQL查詢的結(jié)果變成標(biāo)準(zhǔn)格式,并顯示此結(jié)果以便于用戶查看Zhangsan的細(xì)節(jié)。#p#
攻擊者尋找突破口
首先,攻擊者可能查看應(yīng)用程序是否能夠正確地處理錯(cuò)誤條件。有許多方法可以檢查SQL錯(cuò)誤消息,每一個(gè)方法都依賴于數(shù)據(jù)庫(kù)自身。最常見(jiàn)的例子是“‘”( 撇號(hào))。攻擊者可能會(huì)嘗試插入“‘”而不是一個(gè)合法的用戶名:
Wangzhan.com/userdetail.asp?username=‘
如果出現(xiàn)錯(cuò)誤,攻擊者就可以了解一些信息。例如,下面的錯(cuò)誤就會(huì)使攻擊者知道這是一個(gè)MySQL數(shù)據(jù)庫(kù),而且表明數(shù)據(jù)庫(kù)將“‘”解釋為查詢的一部分,從而揭示出這可能是一個(gè)SQL注入點(diǎn),值得進(jìn)一步調(diào)查。
錯(cuò)誤:您的SQL語(yǔ)法有一個(gè)錯(cuò)誤,請(qǐng)檢查您的MySQL服務(wù)器版本對(duì)應(yīng)的手冊(cè),查看正確的語(yǔ)法…在第4行
在此例中,我們使用了一個(gè)“‘”,但任何“保留”字符,即在測(cè)試數(shù)據(jù)庫(kù)錯(cuò)誤時(shí)可以使用的為特別目的而保留的一個(gè)字符。保留字符對(duì)每種數(shù)據(jù)庫(kù)類型來(lái)說(shuō)都是獨(dú)一無(wú)二的。
借助上面顯示的MySQL錯(cuò)誤消息,我們可以看出黑客是多么聰明,而且能夠發(fā)現(xiàn)應(yīng)用程序正在訪問(wèn)的數(shù)據(jù)庫(kù)表的其它細(xì)節(jié)。請(qǐng)看:
Wangzhan.com/userdetail.asp?username=Zhangsan order by 1
如果我們沒(méi)有收到錯(cuò)誤,就可以知道用戶名要么是SQL WHERE語(yǔ)句中的最后一個(gè)變量(允許我們從一個(gè)數(shù)據(jù)庫(kù)表中重新獲取數(shù)據(jù),同時(shí)又排除其它的無(wú)關(guān)數(shù)據(jù)),或者是WHERE語(yǔ)句中的唯一變量。我們可以讓數(shù)字每次增加1,直至收到一個(gè)錯(cuò)誤。例如,可能在到達(dá)“Zhangsan order by 9”,就可以看到:
錯(cuò)誤:用戶警告:“order clause”查詢中有無(wú)法確認(rèn)的列:SELECT
現(xiàn)在可以確認(rèn),直至提交了“9”,我們才收到了錯(cuò)誤消息,所以可以斷定表中有8列。這個(gè)信息很有用,但我們只是想獲得盡量多的數(shù)據(jù)。假設(shè)沒(méi)有提供輸入驗(yàn)證,通過(guò)在用戶名的位置使用一個(gè)通配符,我們實(shí)際上可以返回所有用戶的細(xì)節(jié):
Wangzhan.com/userdetail.asp?username=%
在該例中,我們將執(zhí)行下面的查詢,返回所有用戶的細(xì)節(jié):
SELECT uname,fname,lname,phone,street,city,state,zip FROM users WHERE user = %
如果攻擊使用此伎倆,勢(shì)必會(huì)造成數(shù)據(jù)損害,使大量的有價(jià)值的客戶信息處于風(fēng)險(xiǎn)之中。其中可能包括應(yīng)當(dāng)被加密的用戶口令,當(dāng)然攻擊者可以在日后再進(jìn)行破解。遭到泄露的客戶信息還有可能包括電子郵件地址,攻擊者可以將其用于釣魚攻擊。
其實(shí),我們可以不用插入簡(jiǎn)單的通配符,而是終止查詢,并讓查詢做一些查詢之外的事情:
Wangzhan.com/userdetail.asp?username=zhangsan;DROP users—
為便于比較,我們將SQL Server的數(shù)據(jù)庫(kù)語(yǔ)句列示如下:
SELECT uname,fname,lname,phone,street,city,state,zip FROM users WHERE user = ‘zhangsan’;DROP users—
還要注意,此例允許你在同一行上提交多個(gè)查詢(在此例中,即SELECT和DROP查詢)。其方法就是用分號(hào)(;)分開(kāi)并用兩個(gè)破折號(hào)結(jié)束。因而,在完成最初的查詢后,攻擊者就可以發(fā)送并運(yùn)行自己選擇的一個(gè)完整查詢。#p#
自動(dòng)攻擊
攻擊者可以使用兩種主要的攻擊方法來(lái)利用SQL注入漏洞:自動(dòng)攻擊和手動(dòng)攻擊。從字面上看似乎很容易理解,但這兩種攻擊在機(jī)制上是非常不同的。自動(dòng)攻擊一般是為特定目的而編制的一種工具所導(dǎo)致的結(jié)果。例如,有的攻擊使用大規(guī)模的注入攻擊,其目的是為了讓其攻擊范圍最大化并任意擴(kuò)散其代碼。這種大規(guī)模的攻擊一般針對(duì)非常具體的應(yīng)用程序架構(gòu),如運(yùn)行ASP的IIS服務(wù)器等。而Asprox攻擊,其目的是為了將一個(gè)JavaScript或iframe標(biāo)記注入到網(wǎng)頁(yè)中,從而傳播病毒。
自動(dòng)SQL注入舉例
下面是一個(gè)高級(jí)SQL注入攻擊的例子,它能夠注入到某些字段類型中。很長(zhǎng)一段時(shí)間以來(lái),此類代碼可以有效的幫助攻擊者傳播病毒。
wangzhan.com/ssp.asp?username=zhangsan’;DECLARE @T VARCHAR (255),@C VARCHAR(255) DECLARE TABLE_CURSOR CURSOR FOR SELECT A.NAME,B.NAME FROM SYSOBJECTS A,SYSCOLUMNS B WHERE A.ID=B.ID AND A.XTYPE=‘U’ AND (B.XTYPE=99 OR
B.XTYPE=35 OR B.XTYPE=231 OR B.XTYPE=167) OPEN TABLE_CURSOR FETCH NEXT
FROM TABLE_CURSOR INTO @T,@C WHILE(@@FETCH_STATUS=0) BEGIN
EXEC(‘UPDATE [‘+@T+’] SET
[‘+@C+’]=RTRIM(CONVERT(VARCHAR(4000),[‘+@C+’]))+’<script code>‘) FETCH NEXT FROM TABLE_CURSOR INTO @T,@C END CLOSE TABLE_CURSOR DEALLOCATE TABLE_CURSOR;--
下面,我們簡(jiǎn)單地看一下這段代碼是如何針對(duì)后端數(shù)據(jù)庫(kù)實(shí)施攻擊的。首先,攻擊者聲明了Table (T) 和 Column (C)這兩個(gè)變量。
DECLARE @T VARCHAR(255),@C VARCHAR(255)
并聲明了一個(gè)可以保存查詢結(jié)果的表cursor:
DECLARE TABLE_CURSOR CURSOR FOR
下面的SELECT語(yǔ)句通過(guò)“text”、“sysname”、“varchar”等列來(lái)檢索所有的用戶對(duì)象,并且將結(jié)果存儲(chǔ)在前面創(chuàng)建的CURSOR中。
SELECT A.NAME,B.NAME FROM SYSOBJECTS A,SYSCOLUMNS B WHERE A.ID=B.ID AND A.XTYPE=‘U’ AND (B.XTYPE=99 OR B.XTYPE=35 OR B.XTYPE=231 OR B.XTYPE=167)
在下面的代碼中,數(shù)據(jù)表CURSOR檢索結(jié)果,并將其分配給表和列變量:
OPEN TABLE_CURSOR FETCH NEXT FROM TABLE_CURSOR INTO @T,@C WHILE(@@FETCH_STATUS=0)
此時(shí),攻擊者已經(jīng)檢索了數(shù)據(jù)庫(kù)中基于文本的這些列,其意圖是為了修改這些列的內(nèi)容。在這里,攻擊者雖然沒(méi)有篡改數(shù)據(jù),但已經(jīng)完成了所有必要的偵察。然后,執(zhí)行更新語(yǔ)句,將JavaScript置于列變量中的每一列中。攻擊完成后,包含Web內(nèi)容(這些內(nèi)容源自數(shù)據(jù)庫(kù)的任何字段)的任何網(wǎng)頁(yè)都會(huì)提交攻擊者的惡意JavaScript代碼。然后,該JavaScript用一個(gè)病毒感染W(wǎng)eb用戶的計(jì)算機(jī):
WHILE(@@FETCH_STATUS=0) BEGIN EXEC(‘UPDATE [‘+@T+’] SET [‘+@C+’]=RTRIM(CONVERT(VARCHAR(4000),[‘+@C+’]))+’<script code>‘) FETCH NEXT FROM TABLE_CURSOR INTO @T,@C END
在注入的結(jié)尾,攻擊者執(zhí)行清理,覆蓋所有的攻擊痕跡:
CLOSE TABLE_CURSOR DEALLOCATE TABLE_CURSOR;--
這些攻擊是完全自動(dòng)化的;黑客攻擊只需使用搜索引擎簡(jiǎn)單地搜索互聯(lián)網(wǎng),查找運(yùn)行經(jīng)典的ASP代碼的Web服務(wù)器即可。別再自欺欺人的相信“我的網(wǎng)站很小,誰(shuí)會(huì)愿意攻擊它呢?”這種愚蠢的謊言。如果你正在通過(guò)互聯(lián)網(wǎng)做商務(wù),不管企業(yè)大小,都易于遭到攻擊。#p#
接管
在很多情況下,攻擊者能夠完全控制SQL服務(wù)器的底層操作系統(tǒng);攻擊者甚至可以接管Web應(yīng)用程序,并最終接管Web服務(wù)器。
接管數(shù)據(jù)庫(kù)服務(wù)器可以導(dǎo)致?lián)p害其它的應(yīng)用程序,甚至損害DMZ中的其它服務(wù)器。現(xiàn)代的Web應(yīng)用程序架構(gòu)一般都有數(shù)據(jù)庫(kù)集群,與其它系統(tǒng)共享數(shù)據(jù)存儲(chǔ),或者位于網(wǎng)絡(luò)中不太安全的地方。如果攻擊者考慮到這個(gè)方面,他就可以使用前面提到的方法繞過(guò)防火墻中一般的IP源過(guò)濾規(guī)則,從而攻擊內(nèi)部網(wǎng)絡(luò),甚至還可以使用SQL服務(wù)器來(lái)存儲(chǔ)病毒、黃色圖片或其它非法內(nèi)容。
此外,通過(guò)首先接管數(shù)據(jù)庫(kù)服務(wù)器,攻擊者可以篡改Web應(yīng)用程序的行為。通常,這種行為包括借助Web服務(wù)器的服務(wù)賬戶在本地服務(wù)器上運(yùn)行命令。如果服務(wù)賬戶有了被提升的特權(quán),攻擊者就可以通過(guò)數(shù)據(jù)庫(kù)服務(wù)器,將命令直接發(fā)送給Web服務(wù)器的操作系統(tǒng)。
有時(shí),數(shù)據(jù)是根據(jù)計(jì)劃例程從DMZ數(shù)據(jù)庫(kù)服務(wù)器析取出來(lái)的。如果通過(guò)公司Intranet(內(nèi)聯(lián)網(wǎng))中的Web接口來(lái)查看數(shù)據(jù),情況就更危險(xiǎn),因?yàn)槎鄶?shù)內(nèi)聯(lián)網(wǎng)的Web應(yīng)用程序在運(yùn)行時(shí),其信任等級(jí)更高。
不要小看盲目攻擊
通常,控制框架會(huì)把SQL錯(cuò)誤搞得不易分辨,如Java或.NET框架。有時(shí),這些錯(cuò)誤是由錯(cuò)誤處理代碼自動(dòng)處理的,或者是由底層的代碼解釋程序處理的。例如,攻擊者可以使用撇號(hào)(‘)而不是合法的輸入:
wangzhan.com/userdetail.asp?username=‘
其結(jié)果為:用戶未找到。
這就告訴我們,Web應(yīng)用程序正在正確地檢查用戶輸入,或者是程序框架正在阻止顯示明顯的錯(cuò)誤消息。在這種情況下,執(zhí)行SQL注入就變得困難了,但并不是不可能。這就引出了下一種攻擊:盲目SQL注入。
盲目SQL注入攻擊是如何工作的呢?它要查看數(shù)據(jù)庫(kù)服務(wù)器是否真正地處理請(qǐng)求,或者查看該請(qǐng)求是否會(huì)觸發(fā)來(lái)自Web服務(wù)器或SQL服務(wù)器的其它響應(yīng)。
例如,我們已經(jīng)看到了能夠向我們提供張三(Zhangsan)用戶細(xì)節(jié)的請(qǐng)求,能夠看出該攻擊是否成功。不過(guò),“WAITFOR DELAY”命令要求SQL服務(wù)器在用查詢結(jié)果響應(yīng)之前,先暫停一分鐘。
wangzhan.com/userdetail.asp?username=zhangsan;WAITFOR DELAY ‘0:1:0’—
如果網(wǎng)站能夠正確地處理用戶輸入,它應(yīng)當(dāng)返回一個(gè)消息,說(shuō)明找不到用戶,或者發(fā)出其它的通知,說(shuō)明“zhangsan;WAITFOR DELAY ‘0:1:0’--”不是一個(gè)合法用戶。
必須指出,只有在將用戶名變量的值被提交給SQL服務(wù)器時(shí),并且Web應(yīng)用程序能夠正確地處理用戶名變量的值時(shí),才會(huì)出現(xiàn)這種情況。
傳統(tǒng)的SQL注入將會(huì)返回錯(cuò)誤,讓用戶知道有關(guān)查詢失敗的原因的細(xì)節(jié)。從本質(zhì)上講,盲目SQL注入依賴的是一種來(lái)自服務(wù)器的布爾邏輯響應(yīng)(是/否,真/假等):查詢請(qǐng)求要么被處理,要么遭遇失敗。盲目SQL注入攻擊一旦得以發(fā)現(xiàn),它就會(huì)提供與典型的SQL注入一樣的功能,但它更難以執(zhí)行,為了獲取信息也需要更多的時(shí)間。#p#
讓盲目攻擊起作用
假設(shè)在示例頁(yè)面中,我們已經(jīng)發(fā)現(xiàn)了盲目注入,我們希望發(fā)現(xiàn)關(guān)于表和數(shù)據(jù)庫(kù)設(shè)計(jì)的細(xì)節(jié)。請(qǐng)看下面的請(qǐng)求:
wangzhan.com/userdetail.asp?username=zhangsan AND ISNULL(ASCII(SUBSTRING((SELECT TOP 1 name FROM sysObjects WHERE xtype=0x55),1,1)),0)>65—
如果我們分解一下,會(huì)看出這個(gè)查詢的結(jié)果實(shí)際上是一個(gè)是或否的回答,“這個(gè)表名的第一個(gè)字符是一個(gè)比65大的ASCII值嗎?”先看最里面的查詢:
SELECT TOP 1 name from sysObjects WHERE xtype=0x55
這意味著:獲取來(lái)自sysObjects(所有的表)列表最上面的一個(gè)名字,其xtype(對(duì)象類型)等于ASCII碼0x55(大寫的字母“U”),轉(zhuǎn)換成用戶(user)表。所以,基本而言,我們獲取了用戶在數(shù)據(jù)庫(kù)中所創(chuàng)建的第一個(gè)表。為簡(jiǎn)單起見(jiàn),假設(shè)這個(gè)表就是“users”:
SUBSTRING(users),1,1
現(xiàn)在,我們創(chuàng)建了一個(gè)子串,它包含了表名users的首個(gè)字符。其值為“u”:
ISNULL(ASCII(u),0)>65
在這里我們查看u的ASCII碼值的結(jié)果是否大于65,確認(rèn)表名以字母開(kāi)頭。如果答案是肯定的,查詢就會(huì)被處理。否則,查詢就不會(huì)被處理。
使用這種方法,我們可以對(duì)每個(gè)查詢簡(jiǎn)單地增加數(shù)字,從而發(fā)現(xiàn)首個(gè)用戶名的第一個(gè)字母。例如,假設(shè)我們?cè)诖笥?17時(shí)(>117)得到了一個(gè)否定的響應(yīng),我們知道第一個(gè)字母是字母“u”,因?yàn)?ldquo;u”的ASCII值是117。在發(fā)現(xiàn)這一點(diǎn)之后,我們可以簡(jiǎn)單地改變SUBSTRING參數(shù)來(lái)選擇第二個(gè)字母,然后是第三個(gè)字母,等等。
最后,在沒(méi)有錯(cuò)誤代碼時(shí),我們借助于盲目注入就可以發(fā)現(xiàn)有漏洞的Web應(yīng)用程序的數(shù)據(jù)庫(kù)的完整的表結(jié)構(gòu)。#p#
防御措施:保證應(yīng)用程序編碼的安全
安全的編碼技術(shù)可以清除造成SQL注入攻擊的漏洞。下面說(shuō)的是Web應(yīng)用程序安全編碼的三個(gè)基本方法。
方法一:輸入驗(yàn)證
在Web應(yīng)用程序這一層防止SQL注入最常見(jiàn)的方法是使用輸入驗(yàn)證。無(wú)論是何種語(yǔ)言或平臺(tái),這種方法都很有用。其實(shí)質(zhì)就是在驗(yàn)證用戶輸入的大小和類型前,不對(duì)其采取行動(dòng)。如果你期望用戶輸入的是數(shù)字,就不要接受非數(shù)字的東西。
例如,下面的URL:
wangzhan.com/userdetail.asp?userid=9899
很明顯,在這個(gè)GET請(qǐng)求中,我們期望輸入一個(gè)整數(shù)。一個(gè)簡(jiǎn)單的類型檢查會(huì)告訴我們這是不是一個(gè)合法的字符,從而確保應(yīng)用程序不會(huì)處理非數(shù)字值的輸入。
if (is_numeric($userid)){}
此外,如果用戶的ID總是四個(gè)字符的長(zhǎng)度,我們就可以進(jìn)一步采取措施,除了使用常規(guī)的表達(dá)式來(lái)執(zhí)行整型檢查,還可以強(qiáng)化邊界檢查。
if (preg_match(‘\d{4}’, $string)) {}
在對(duì)待如何驗(yàn)證用戶輸入值的這個(gè)問(wèn)題上,我們僅受到自己創(chuàng)造力的限制。這里的關(guān)鍵是驗(yàn)證由用戶發(fā)送并由系統(tǒng)使用的每一個(gè)值。
執(zhí)行類型檢查的另外一種方法是通過(guò)ASCII字符。用戶名一般是由字母和數(shù)字組成的,所以我們不希望看到類似“@”、“;”之類的字符。因而,我們可以解析用戶名變量,看看是否存在著不屬于48-57,65-90,97-122的任何ASCII字符。在這個(gè)范圍之外的任何ASCII字符對(duì)于用戶名變量來(lái)說(shuō),都是不合法的,應(yīng)當(dāng)拒絕接受。這就是所謂白名單的一個(gè)例子。
知道白名單和黑名單的區(qū)別非常重要。白名單僅接受已知為安全的值或字符,如字母和數(shù)字。而黑名單則會(huì)阻止或不接受已知為惡意的字符。
方法二:規(guī)避技術(shù)
到目前為止,類型檢查和邊界檢查似乎很容易,但并非在檢查所有的數(shù)據(jù)類型時(shí)都會(huì)這么簡(jiǎn)單。許多情況下,我們還會(huì)使用VARCHAR數(shù)據(jù)類型(VARCHAR是一種比CHAR更加靈活的數(shù)據(jù)類型,同樣用于表示字符數(shù)據(jù),但是VARCHAR可以保存可變長(zhǎng)度的字符串。)此類型有可能包含危險(xiǎn)字符。這在備注字段和其它的長(zhǎng)表單文本字段中很常見(jiàn)。
在這種情況下,我們可以利用一種稱為規(guī)避的技術(shù)來(lái)確保變量的內(nèi)容絕對(duì)不會(huì)被解析為SQL語(yǔ)句的一部分。
請(qǐng)看下面這個(gè)例子中的請(qǐng)求:
wangzhan.com/comment.asp?msg=I’m zhangsan.
在這個(gè)例子中,有一個(gè)撇號(hào)(’),這是一種常被認(rèn)為是惡意字符的字符(請(qǐng)參考上一篇文章提到的撇號(hào)),我們并不希望排除它,因?yàn)榇颂幩挠梅ㄊ呛戏ǖ模覀円膊幌M芙^這個(gè)消息。
例如,在PHP中,我們可以使用mysql_real_escape_string函數(shù):
mysql_real_escape_string($GET[‘msg’]);
這就不會(huì)導(dǎo)致安全問(wèn)題,而是安全地解決了撇號(hào)問(wèn)題,使其不能用于任何MySQL查詢中:
msg=“Hello I\’m zhangsan”
同樣地,在微軟的.NET架構(gòu)中,設(shè)計(jì)者常用REPLACE來(lái)保證字符串的安全。在下面的例子中,REPLACE函數(shù)將撇號(hào)(’)放在引號(hào)中,使其成為一種安全字符:
sql = replace(str, “’“, “’“)
方法三:參數(shù)化查詢
防止SQL注入的第三種方法是一種稱為參數(shù)化查詢的技術(shù)。這種方法非常有效,因?yàn)樗梢苑浅?yán)密地控制SQL語(yǔ)句的組成結(jié)構(gòu)。此方法在將對(duì)SQL語(yǔ)句的任何重要變更交給SQL服務(wù)器處理之前就拒絕其操作。
下面的Java例子中,我們簡(jiǎn)單地將參數(shù)添加到已經(jīng)構(gòu)建的靜態(tài)查詢中。首先,我們使用問(wèn)號(hào)作為變量建立了真實(shí)的SELECT語(yǔ)句:
String query = “SELECT account_balance FROM user_data WHERE user_name = ? “;
下一步,我們調(diào)用prepareStatement函數(shù):
PreparedStatement pstmt = connection.prepareStatement( query );
然后,在查詢中我們將字符串“custname”指派給變量:
pstmt.setString( 1, custname);
最后,我們執(zhí)行查詢,并將結(jié)果存儲(chǔ)在一個(gè)變量中:
ResultSet results = pstmt.executeQuery( );
通過(guò)使用這種方法,我們能夠確保在附加的惡意查詢或參數(shù)被發(fā)送給數(shù)據(jù)庫(kù)之前,不會(huì)被添加到查詢中。注意,應(yīng)當(dāng)像前面所討論的那樣來(lái)驗(yàn)證“custname”變量,因?yàn)樗遣皇苄湃蔚挠脩糨斎搿?/p>
【編輯推薦】




















