PHP中防止SQL注入_第1頁
PHP中防止SQL注入_第2頁
PHP中防止SQL注入_第3頁
PHP中防止SQL注入_第4頁
PHP中防止SQL注入_第5頁
已閱讀5頁,還剩10頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、在本系列文章中, 我們將全面探討如何在PHP 開發(fā)環(huán)境中全面阻止SQL注入式攻 擊,并給出一個具體的開發(fā)示例。一、 引言PHP是一種力量強大但相當(dāng)容易學(xué)習(xí)的服務(wù)器端腳本語言,即使是經(jīng)驗不多 的程序員也能夠使用它來創(chuàng)建復(fù)雜的動態(tài)的web站點。然而,它在實現(xiàn)因特網(wǎng)服 務(wù)的秘密和安全方面卻常常存在許多困難。在本系列文章中,我們將向讀者介紹 進行web開發(fā)所必需的安全背景以及PHP特定的知識和代碼-你可以借以保護你 自己的web應(yīng)用程序的安全性和一致性。首先,我羌虻鼗毓艘幌路衿靼踩侍?展示你如何存取一個共享宿主環(huán)境下的私人信息,使開發(fā)者脫離開生產(chǎn)服務(wù) 器,維持最新的軟件,提供加密的頻道,并且控制對你的

2、系統(tǒng)的存取。然后,我們討論PHP腳本實現(xiàn)中的普遍存在的脆弱性。我們將解釋如何保護 你的腳本免于SQL注入,防止跨站點腳本化和遠程執(zhí)行,并且阻止對臨時文件及 會話的"劫持"。在最后一篇中,我們將實現(xiàn)一個安全的Web應(yīng)用程序。你將學(xué)習(xí)如何驗證用 戶身份,授權(quán)并跟蹤應(yīng)用程序使用,避免數(shù)據(jù)損失,安全地執(zhí)行高風(fēng)險性的系統(tǒng) 命令,并能夠安全地使用web服務(wù)。無論你是否有足夠的PHP安全開發(fā)經(jīng)驗,本 系列文章都會提供豐富的信息來幫助你構(gòu)建更為安全的在線應(yīng)用程序。二、 什么是SQL注入如果你打算永遠不使用某些數(shù)據(jù)的話, 那么把它們存儲于一個數(shù)據(jù)庫是毫無 意義的; 因為數(shù)據(jù)庫的設(shè)計目的是為了

3、方便地存取和操作數(shù)據(jù)庫中的數(shù)據(jù)。 但是, 如果只是簡單地這樣做則有可能會導(dǎo)致潛在的災(zāi)難。 這種情況并不主要是因為你 自己可能偶然刪除數(shù)據(jù)庫中的一切;而是因為,當(dāng)你試圖完成某項"無辜"的任務(wù) 時, 你有可能被某些人所"劫持"-使用他自己的破壞性數(shù)據(jù)來取代你自己的數(shù)據(jù)。 我們稱這種取代為"注入"。其實,每當(dāng)你要求用戶輸入構(gòu)造一個數(shù)據(jù)庫查詢,你是在允許該用戶參與構(gòu) 建一個存取數(shù)據(jù)庫服務(wù)器的命令。 一位友好的用戶可能對實現(xiàn)這樣的操作感覺很 滿意;然而,一位惡意的用戶將會試圖發(fā)現(xiàn)一種方法來扭曲該命令,從而導(dǎo)致該 被的扭曲命令刪除數(shù)據(jù),甚至做出更

4、為危險的事情。作為一個程序員,你的任務(wù) 是尋找一種方法來避免這樣的惡意攻擊。三、 SQL注入工作原理構(gòu)造一個數(shù)據(jù)庫查詢是一個非常直接的過程。典型地,它會遵循如下思路來 實現(xiàn)。僅為說明問題,我們將假定你有一個葡萄酒數(shù)據(jù)庫表格"wines",其中有 一個字段為"variety"(即葡萄酒類型:1. 提供一個表單-允許用戶提交某些要搜索的內(nèi)容。 讓我們假定用戶選擇搜 索類型為"lagrein"的葡萄酒。2. 檢索該用戶的搜索術(shù)語, 并且保存它-通過把它賦給一個如下所示的變量 來實現(xiàn):$variety = $_POST'variety

5、'因此,變量$variety的值現(xiàn)在為:lagrein3. 然后,使用該變量在WHERE子句中構(gòu)造一個數(shù)據(jù)庫查詢:$query = "SELECT * FROM wines WHERE variety='$variety'"所以,變量$query的值現(xiàn)在如下所示:SELECT * FROM wines WHERE variety='lagrein'4. 把該查詢提交給MySQL服務(wù)器。5. MySQL返回wines表格中的所有記錄-其中,字段variety的值為 "lagrein"。到目前為止,這應(yīng)該是一個你所熟悉

6、的而且是非常輕松的過程。遺憾的是,有時 我們所熟悉并感到舒適的過程卻容易導(dǎo)致我們產(chǎn)生自滿情緒。現(xiàn)在,讓我們再重 新分析一下剛才構(gòu)建的查詢。1. 你創(chuàng)建的這個查詢的固定部分以一個單引號結(jié)束,你將使用它來描述變 量值的開始:$query = " SELECT * FROM wines WHERE variety = '"2. 使用原有的固定不變的部分與包含用戶提交的變量的值:$query .= $variety;3. 緩螅閌褂昧硪桓齙爬戳喲私峁?描述該變量值的結(jié)束:$ query .= "'"于是,$query的值如下所示:SELECT *

7、FROM wines WHERE variety = 'lagrein'這個構(gòu)造的成功依賴用戶的輸入。在本文示例中,你正在使用單個單詞(也可能是一組單詞來指明一種葡萄酒類型。因此,該查詢的構(gòu)建是無任何問題的, 并且結(jié)果也會是你所期望的-一個葡萄酒類型為"lagrein"的葡萄酒列表?,F(xiàn)在, 讓我們想象, 既然你的用戶不是輸入一個簡單的類型為"lagrein"的葡萄酒類型, 而是輸入了下列內(nèi)容(注意包括其中的兩個標點符號:lagrein' or 1=1;現(xiàn)在, 你繼續(xù)使用前面固定的部分來構(gòu)造你的查詢(在此, 我們僅顯示$query

8、變量的結(jié)果值:SELECT * FROM wines WHERE variety = '然后,你使用包含用戶輸入內(nèi)容的變量的值與之進行連接(在此,以粗體顯 示:SELECT * FROM wines WHERE variety = 'lagrein' or 1=1;最后,添加上下面的下引號:SELECT * FROM wines WHERE variety = 'lagrein' or 1=1;'于是,這個查詢結(jié)果與你的期望會相當(dāng)不同。事實上,現(xiàn)在你的查詢包含的 不是一條而是兩條指令,因為用戶輸入的最后的分號已經(jīng)結(jié)束了第一條指令(進 行記錄選擇從

9、而開始了一條新的指令。在本例中,第二條指令,除了一個簡單 的單引號之外別無意義;但是,第一條指令也不是你所想實現(xiàn)的。當(dāng)用戶把一個 單引號放到他的輸入內(nèi)容的中間時,他結(jié)束了期望的變量的值,并且引入了另一 個條件。因此,不再是檢索那些variety為"lagrein"的記錄,而是在檢索那些 滿足兩個標準中任何一個(第一個是你的,而第二個是他的-variety為 "lagrein"或1等于1的記錄。既然1總是1,因此,你會檢索到所有的記錄!你可能反對: 我不會使用雙引號來代替單引號來描述用戶提交的變量嗎?不 錯,這至少可以減慢惡意用戶的攻擊。(在以前的文章中,

10、我們提醒過你:應(yīng)該 禁止所有對用戶的錯誤通知信息。如果在此生成一條錯誤消息,那么,它有可能 恰恰幫助了攻擊者-提供一個關(guān)于他的攻擊為什么失敗的具體的解釋。在實踐中, 使你的用戶能夠看到所有的記錄而不只是其中的一部分乍看起來 似乎不太費事,但實際上,這的確費事不少;看到所有的記錄能夠很容易地向他 提供有關(guān)于該表格的內(nèi)部結(jié)構(gòu), 從而也就向他提供了使其以后實現(xiàn)更為惡毒目的 的一個重要參考。 如果你的數(shù)據(jù)庫中不是包含顯然無害的酒之類信息而是包含例 如一個含有雇員年收入的列表,那么,剛才描述情形會是特別真實的。而從理論角度分析,這種攻擊也的確是一件很可怕的事情。由于把意外的內(nèi) 容注入到你的查詢中,所以,

11、此用戶能夠?qū)崿F(xiàn)把你的數(shù)據(jù)庫存取轉(zhuǎn)化為用于實現(xiàn) 他自己的目的。因此現(xiàn)在,你的數(shù)據(jù)庫已經(jīng)對他打開-正如對你敞開一樣。四、 PHP和MySQL注入如我們前面所描述的,PHP,從本身設(shè)計來說,并沒有做什么特別的事情- 除了按照你的指示操作之外。因此,如果為惡意用戶所用,它也只是按照要求" 允許"特別設(shè)計的攻擊-例如我們前面所描述的那樣。我們將假定, 你不會故意地或甚至是偶然地構(gòu)造一個具有破壞性效果的數(shù)據(jù)庫查 詢-于是,我們假定問題出在來自你的用戶的輸入方面?,F(xiàn)在,讓我們來更為細 致地分析一下用戶可能向你的腳本提供信息的各種途徑。五、 用戶輸入的類型如今,用戶能夠影響你的腳本的行為已

12、變得越來越復(fù)雜。用戶輸入最明顯的來源當(dāng)然是表單上的一個文本輸入域。使用這樣的一個 域,你簡直是在故意教唆一個用戶輸入任意數(shù)據(jù)。而且,你向用戶提供了一個很 大的輸入范圍;沒有什么辦法能夠使你提前限制一個用戶能夠輸入的數(shù)據(jù)類型 (盡管你能夠選擇限制它的長度。 這正是絕大多數(shù)的注入式攻擊源主要來自于無 防備的表單域的原因。但是,還存在其它的攻擊源,并且稍加思考你就會想到的一種潛于表單后臺 的技術(shù)-POST方法!通過簡單地分析顯示在瀏覽器的導(dǎo)航工具欄中的URI,一個 善于觀察的用戶能夠很容易地看出是什么信息傳遞到了一個腳本。 盡管典型情況 下這樣的URI是以編程方式生成的,但是,沒有什么辦法能夠阻止一

13、個惡意的用 戶簡單地把一個帶有一個不適當(dāng)?shù)淖兞恐档腢RI輸入到一個瀏覽器中-而這樣潛 在地打開一個可能會被其濫用的數(shù)據(jù)庫。限制用戶輸入內(nèi)容的一個常用策略是在一個表單中提供一個選擇框, 而不是 一個輸入框。這種控件能夠強制用戶從一組預(yù)定義的值中進行選擇,并且能夠在 一定程度上阻止用戶輸入期望不到的內(nèi)容。 但是正如一個攻擊者可能"哄騙"一個 URI(也即是,創(chuàng)建一個能夠模仿一個可信任的卻無效的URI一樣,他也可能模 仿創(chuàng)建你的表單及其自己的版本, 并因此在選項框中使用非法的而不是預(yù)定義的安全選擇。要實現(xiàn)這點是極其簡單的;他僅需要觀察源碼,然后剪切并且粘貼該 表單的源代碼-然后一

14、切為他敞開大門。在修改該選擇之后,他就能夠提交表單,并且他的無效的指令就會被接受, 就象它們是原始的指令一樣。因此,該用戶可以使用許多不同的方法試圖把惡意 的代碼注入到一個腳本中。上篇文章我們介紹了PHP中防止SQL注入式攻擊一,本文我們來繼續(xù)學(xué)習(xí), php防SQL注入式攻擊。一、注入式攻擊的類型可能存在許多不同類型的攻擊動機,但是乍看上去,似乎存在更多的類型。 這是非常真實的-如果惡意用戶發(fā)現(xiàn)了一個能夠執(zhí)行多個查詢的辦法的話。本文 后面,我們會對此作詳細討論。如果你的腳本正在執(zhí)行一個SELECT指令,那么,攻擊者可以強迫顯示一個 表格中的每一行記錄-通過把一個例如"1=1"

15、;這樣的條件注入到WHERE子句中, 如 下所示(其中,注入部分以粗體顯示:SELECT * FROM wines WHERE variety = 'lagrein' OR 1=1;'正如我們在前面所討論的,這本身可能是很有用的信息,因為它揭示了該表 格的一般結(jié)構(gòu)(這是一條普通的記錄所不能實現(xiàn)的, 以及潛在地顯示包含機密信 息的記錄。一條更新指令潛在地具有更直接的威脅。通過把其它屬性放到SET子句中, 一名攻擊者可以修改當(dāng)前被更新的記錄中的任何字段,例如下面的例子(其中, 注入部分以粗體顯示:UPDATE wines SET type='red',

16、9;vintage'='9999' WHERE variety = 'lagrein' 通過把一個例如1=1這樣的恒真條件添加到一條更新指令的WHERE子句中, 這種修改范圍可以擴展到每一條記錄,例如下面的例子(其中,注入部分以粗體 顯示:UPDATE wines SET type='red','vintage'='9999 WHERE variety = 'lagrein' OR 1=1;'最危險的指令可能是DELETE-這是不難想像的。其注入技術(shù)與我們已經(jīng)看到 的相同-通過修改WHERE

17、子句來擴展受影響的記錄的范圍,例如下面的例子(其 中,注入部分以粗體顯示:DELETE FROM wines WHERE variety = 'lagrein' OR 1=1;'二、多個查詢注入多個查詢注入將會加劇一個攻擊者可能引起的潛在的損壞-通過允許多條破 壞性指令包括在一個查詢中。在使用MySQL數(shù)據(jù)庫時,攻擊者通過把一個出乎意 料之外的終止符插入到查詢中即可很容易實現(xiàn)這一點-此時一個注入的引號(單 引號或雙引號標記期望變量的結(jié)尾;然后使用一個分號終止該指令?,F(xiàn)在,一 個另外的攻擊指令可能被添加到現(xiàn)在終止的原始指令的結(jié)尾。 最終的破壞性查詢 可能看起來如下所示:S

18、ELECT * FROM wines WHERE variety = 'lagrein'GRANT ALL ON *.* TO 'BadGuy%' IDENTIFIED BY 'gotcha''這個注入將創(chuàng)建一個新的用戶BadGuy并賦予其網(wǎng)絡(luò)特權(quán)(在所有的表格上 具有所有的特權(quán);其中,還有一個"不祥"的口令被加入到這個簡單的SELECT 語句中。如果你遵循我們在以前文章中的建議-嚴格限制該過程用戶的特權(quán),那 么,這應(yīng)該無法工作,因為web服務(wù)器守護程序不再擁有你撤回的GRANT特權(quán)。 但是從理論上講,這樣的一個攻擊可

19、能給予BadGuy自由權(quán)力來實現(xiàn)他對你的數(shù) 據(jù)庫的任何操作。至于這樣的一個多查詢是否會被MySQL服務(wù)器處理,結(jié)論并不唯一。這其中 的一些原因可能是由于不同版本的MySQL所致, 但是大多數(shù)情況卻是由于多查詢 存在的方式所致。MySQL的監(jiān)視程序完全允許這樣的一個查詢。常用的MySQL GUI-phpMyAdmin,在最終查詢之前會復(fù)制出以前所有的內(nèi)容,并且僅僅這樣做。但是, 大多數(shù)的在一個注入上下文中的多查詢都是由PHP的mysql擴展負責(zé) 管理的。幸好,默認情況下,它是不允許在一個查詢中執(zhí)行多個指令的;試圖執(zhí) 行兩個指令(例如上面所示的注入將會簡單地導(dǎo)致失敗-不設(shè)置任何錯誤,并且 沒有生成

20、任何輸出信息。在這種情況下,盡管PHP也只是"規(guī)規(guī)矩矩"地實現(xiàn)其缺 省行為,但是確實能夠保護你免于大多數(shù)簡單的注入式攻擊。PHP5中的新的mysqli擴展(參考 樣,內(nèi)在地也不支持多個查詢,不過卻提供了一個mysqli_multi_query(函數(shù) 以支持你實現(xiàn)多查詢-如果你確實想這樣做的話。然而,對于SQLite-與PHP5綁定到一起的可嵌入的SQL數(shù)據(jù)庫引擎(參考 /和 用而吸引了大量用戶的關(guān)注。在有些情況下,SQLite缺省地允許這樣的多指令 查詢,因為該數(shù)據(jù)庫可以優(yōu)化批查詢,特別是非常有效的批INSERT語句處理。 然而,如果查詢的結(jié)

21、果為你的腳本所使用的話(例如在使用一個SELECT語句檢 索記錄的情況下,sqlite_query(函數(shù)卻不會允許執(zhí)行多個查詢。三、INVISION Power BOARD SQL注入脆弱性Invision Power Board是一個著名的論壇系統(tǒng)。2005年五月6號,在登錄 代碼中發(fā)現(xiàn)了一處SQL注入脆弱性。其發(fā)現(xiàn)者為GulfTech Security Research 的James Bercegay。這個登錄查詢?nèi)缦滤?$DB->query("SELECT * FROM ibf_members WHERE id=$mid ANDpassword='$pid

22、9;"其中,成員ID變量$mid和口令I(lǐng)D變量$pid被使用下面兩行代碼從my_cookie(函數(shù)中檢索出:$mid = intval($std->my_getcookie('member_id'$pid = $std->my_getcookie('pass_hash'在此,my_cookie(函數(shù)使用下列語句從cookie中檢索要求的變量: return urldecode($_COOKIE$ibforums->vars'cookie_id'.$name;【注意】從該cookie返回的值根本沒有被處理。盡管$mid在

23、使用于查詢之 前被強制轉(zhuǎn)換成一個整數(shù),但是$pid卻保持不變。因此,它很容易遭受我們前 面所討論的注入類型的攻擊。因此,通過以如下方式修改my_cookie(函數(shù),這種脆弱性就會暴露出來:if (!in_array( $name,array('topicsread', 'forum_read','collapseprefs'return $this->clean_value(urldecode($_COOKIE$ibforums->vars'cookie_id'.$name; elsereturn urldecode(

24、$_COOKIE$ibforums->vars'cookie_id'.$name;經(jīng)過這樣的改正之后,其中的關(guān)鍵變量在"通過"全局clean_value(函數(shù)后 被返回,而其它變量卻未進行檢查?,F(xiàn)在,既然我們大致了解了什么是SQL注入,它的注入原理以及這種注入的 脆弱程度,那么接下來,讓我們探討如何有效地預(yù)防它。幸好,PHP為我們提供 了豐富的資源,因此我們有充分的信心預(yù)言,一個經(jīng)仔細地徹底地使用我們所推 薦的技術(shù)構(gòu)建的應(yīng)用程序?qū)哪愕哪_本中根本上消除任何可能性的SQL注入- 通過在它可能造成任何損壞之前"清理"你的用戶的數(shù)據(jù)來實

25、現(xiàn)。四、界定你的查詢中的每一個值我們推薦,你確保界定了你的查詢中的每一個值。字符串值首當(dāng)其沖,以及 那些你通常期望應(yīng)該使用"單"(而不是"雙"引號的內(nèi)容。一方面,如果你使用雙 引號來允許PHP在字符串內(nèi)的變量替代,這樣可以使得輸入查詢更為容易些;另 一方面,這(無可否認,只是極少量地也會減少以后PHP代碼的分析工作。下面,讓我們使用我們一開始使用的那個非注入式查詢來說明這個問題:SELECT * FROM wines WHERE variety = 'lagrein'或以PHP語句表達為:$query = "SELECT * F

26、ROM wines WHERE variety = '$variety'"從技術(shù)上講,引號對于數(shù)字值來說是不需要使用的。但是,如果你并不介意 用引號把例如葡萄酒這樣的一個域相應(yīng)的一個值括起來并且如果你的用戶把一 個空值輸入到你的表單中的話,那么,你會看到一個類似下面的查詢:SELECT * FROM wines WHERE vintage =當(dāng)然,這個查詢從語法上講是無效的;但是,下面的語法卻是有效的:SELECT * FROM wines WHERE vintage = ''第二個查詢將(大概不會返回任何果,但是至少它不會返回一個錯誤消息。五、檢查用

27、戶提交的值的類型從前面的討論中我們看到,迄今為止,SQL注入的主要來源往往出在一個意 料之外的表單入口上。然而,當(dāng)你經(jīng)由一個表單向用戶提供機會提交某些值時, 你應(yīng)該有相當(dāng)?shù)膬?yōu)勢來確定你想取得什么樣的輸入內(nèi)容-這可以使得我們比較容 易地檢查用戶入口的有效性。 在以前的文章中, 我們已經(jīng)討論過這樣的校驗問題; 所以, 在此, 我們僅簡單地總結(jié)當(dāng)時我們討論的要點。 如果你正在期望一個數(shù)字, 那么你可以使用下面這些技術(shù)之一來確保你得到的真正.· 使用is_int(函數(shù)(或is_integer(或is_long(。· 使用gettype(函數(shù)。· 使用intval(函數(shù)。&

28、#183; 使用settype(函數(shù)。為了檢查用戶輸入內(nèi)容的長度,你可以使用strlen(函數(shù)。為了檢查一個 期望的時間或日期是否有效,你可以使用strtotime(函數(shù)。它幾乎一定能夠確 保一位用戶的入口中沒有包含分號字符(除非標點符號可以被合法地包括在內(nèi)。 你可以借助于strpos(函數(shù)容易地實現(xiàn)這一點,如下所示:if( strpos( $variety, '' exit ( "$variety is an invalid value for variety!" ;正如我們在前面所提到的,只要你仔細分析你的用戶輸入期望,那么,你應(yīng) 該能夠很容易地檢查出其

29、中存在的許多問題。六、從你的查詢中濾去每一個可疑字符盡管在以前的文章中,我們已經(jīng)討論過如何過濾掉危險字符的問題;但是在 此,還是讓我們再次簡單地強調(diào)并歸納一下這個問題:· 不要使用magic_quotes_gpc指令或它的"幕后搭擋"-addslashes(函 數(shù),此函數(shù)在應(yīng)用程序開發(fā)中是被限制使用的,并且此函數(shù)還要求使用額外的步 驟-使用stripslashes(函數(shù)。· 相比之下,mysql_real_escape_string(函數(shù)更為常用,但是也有它自 己的缺點。-一、 建立一個安全抽象層我們并不建議你手工地把前面介紹的技術(shù)應(yīng)用于每一個用戶輸入的

30、實例中, 而是強烈推薦你為此創(chuàng)建一個抽象層。 一個簡單的抽象是把你的校驗方案加入到 一個函數(shù)中,并且針對用戶輸入的每一項調(diào)用這個函數(shù)。當(dāng)然,我們還可以創(chuàng)建 一種更復(fù)雜的更高一級的抽象-把一個安全的查詢封裝到一個類中,從而應(yīng)用于 整個應(yīng)用程序。在網(wǎng)上已經(jīng)存在許多這種現(xiàn)成的免費的類;在本篇中,我們正要 討論其中的一些。進行這種抽象至少存在三個優(yōu)點(而且每一個都會改進安全級別:1. 本地化代碼。2. 使查詢的構(gòu)造更快且更為可靠-因為這可以把部分工作交由抽象代碼來 實現(xiàn)。3. 當(dāng)基于安全特征進行構(gòu)建并且恰當(dāng)使用時,這將會有效地防止我們前面 所討論的各種各樣的注入式攻擊。二、 改進現(xiàn)有的應(yīng)用程序如果你想

31、改進一個現(xiàn)有的應(yīng)用程序,則使用一個簡單的抽象層是最適當(dāng)?shù)摹?一個能夠簡單地"清理"你所收集的任何用戶輸入內(nèi)容的函數(shù)可能看起來如下所 示:function safe( $string return "'" . mysql_real_escape_string( $string . "'"【注意】我們已經(jīng)構(gòu)建了相應(yīng)于值要求的單引號以及mysql_real_escape_string(函數(shù)。接下來,就可以使用這個函數(shù)來構(gòu)造一個 $query變量,如下所示:$variety = safe( $_POST'variety

32、' ;$query = " SELECT * FROM wines WHERE variety=" . $variety;現(xiàn)在,你的用戶試圖進行一個注入式攻擊-通過輸入下列內(nèi)容作為變量 $variety 的值: lagrein' or 1=1; 注意,如果不進行上面的"清理",則最后的查詢將如下所示(這將導(dǎo)致無法 預(yù)料的結(jié)果): SELECT * FROM wines WHERE variety = 'lagrein' or 1=1;' 然而現(xiàn)在, 既然用戶的輸入已經(jīng)被清理,那么查詢語句就成為下面這樣一種 無危害的

33、形式: SELECT * FROM wines WHERE variety = 'lagrein/' or 1=1/;' 既然數(shù)據(jù)庫中不存在與指定的值相應(yīng)的 variety 域(這正是惡意用戶所輸入的內(nèi) 容-lagrein' or 1=1;,那么,這個查詢將不能返回任何結(jié)果,并且注入將會失 敗。 三、 保護一個新的應(yīng)用程序 如果你正在創(chuàng)建一個新的應(yīng)用程序,那么,你可以從頭開始創(chuàng)建一個安全抽 象層。如今,PHP 5 新改進的對于 MySQL 的支持(這主要體現(xiàn)在新的 mysqli 擴 展中)為這種安全特征提供了強有力的支持(既有過程性的,也有面向?qū)ο筇卣?的)。你

34、可以從站點 上獲取有關(guān) mysqli 的信息。注意, 只有當(dāng)你使用-with-mysqli=path/to/mysql_config 選項編譯 PHP 時,這種 mysqli 支持才可用。 下面是該代碼的一個過程性版本, 用于保護一個基于 mysqli 的查詢: ?php /檢索用戶的輸入 $animalName = $_POST'animalName' /連接到數(shù)據(jù)庫 $connect = mysqli_connect( 'localhost', 'username', 'password', 'database'

35、; ; if ( !$connect exit( 'connection failed: ' . mysqli_connect_error( ; /創(chuàng)建一個查詢語句源 $stmt = mysqli_prepare( $connect,"SELECT intelligence FROM animals WHERE name = ?" ; if ( $stmt /把替代綁定到語句上 mysqli_stmt_bind_param( $stmt, "s", $animalName ; /執(zhí)行該語句 mysqli_stmt_execute( $st

36、mt ; /檢索結(jié)果. mysqli_stmt_bind_result( $stmt, $intelligence ; / .并顯示它 if ( mysqli_stmt_fetch( $stmt print "A $animalName has $intelligence intelligence./n" else print 'Sorry, no records found.' /清除語句源 mysqli_stmt_close( $stmt ; mysqli_close( $connect ; ? 在上面的片斷中,首先收集用戶提交的輸入內(nèi)容并建立數(shù)據(jù)庫連接

37、。然后,使用 mysqli_prepare(函數(shù)創(chuàng)建一個查詢語句源-在此命名為$stmt 以反映使用它的 函數(shù)的名稱。這個函數(shù)使用了兩個參數(shù):連接資源和一個字符串(每當(dāng)你使用擴 展插入一個值時,"?"標記被插入到其中)。在本例中,你僅有一個這樣的值動物的名字。 注意, 在一個 SELECT 語句中,放置"?"標記的唯一的有效位置是在值比較部 分。這正是為什么你不需要指定使用哪個變量的原因(除了在 mysqli_stmt_bind_param(函數(shù)中之外)。在此,你還需要指定它的類型-在本 例中,"s"代表字符串。其它可能的類型有:&q

38、uot;I"代表整數(shù),"d"代表雙精度數(shù)(或 浮點數(shù),而"b"代表二進制字符串。 函數(shù) mysqli_stmt_execute(,mysqli_stmt_bind_result(和 mysqli_stmt_fetch(負責(zé)執(zhí)行查詢并檢索結(jié)果。如果存在檢索結(jié)果,則顯示它 們;如果不存在結(jié)果,則顯示一條無害的消息。最后,你需要關(guān)閉$stmt 資源以 及數(shù)據(jù)庫連接-從內(nèi)存中對它們加以釋放。 假定一個合法的用戶輸入了字符串"lemming", 那么這個例程將(假定是數(shù)據(jù) 庫中適當(dāng)?shù)臄?shù)據(jù)輸出消息"A lemming has

39、very low intelligence."。假定存 在一個嘗試性注入-例如"lemming' or 1=1;",那么這個例程將打印(無害消息 "Sorry, no records found."。 此外,mysqli 擴展還提供了一個面向?qū)ο蟀姹镜南嗤睦?。下面,我們想說 明這種版本的使用方法。 ?php $animalName = $_POST'animalName' $mysqli = new mysqli( 'localhost', 'username', 'password', 'database' if ( !$mysqli exit( 'connection failed: ' . mysqli_connect_error( ; $s

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論