■ 河南 劉建臣
編者按:對(duì)于目前的網(wǎng)絡(luò)安全形式來(lái)說(shuō),跨站腳本攻擊是黑客最常用的攻擊方式之一。當(dāng)然,和SQL調(diào)用相關(guān)的安全隱患同樣不可忽視,這其實(shí)就是大家很熟悉的SQL注入問(wèn)題。雖說(shuō)現(xiàn)在網(wǎng)站管理者的安全意識(shí)不斷提高,但是還有相當(dāng)數(shù)量的網(wǎng)站存在SQL注入漏洞,這給黑客帶來(lái)了可乘之機(jī)。因此,對(duì)SQL調(diào)用進(jìn)行嚴(yán)格的管理,對(duì)于提高網(wǎng)站安全性是極為重要的。
對(duì)于SQL注入漏洞來(lái)說(shuō),主要是因?yàn)镾QL語(yǔ)句調(diào)用方法不當(dāng)所產(chǎn)生的安全隱患。如果在網(wǎng)站程序中存在該漏洞,就會(huì)招致黑客直接對(duì)服務(wù)器進(jìn)行主動(dòng)攻擊,導(dǎo)致數(shù)據(jù)庫(kù)中的信息被竊取或被惡意篡改、讓登錄認(rèn)證形同虛設(shè)、對(duì)服務(wù)器上的文件進(jìn)行非法讀取或修改、隨意執(zhí)行服務(wù)器程序等不良后果。
可以說(shuō)只要是調(diào)用SQL語(yǔ)句的位置,都可能存在注入漏洞,其可能影響到所有的頁(yè)面。
兵法云,知己知彼百戰(zhàn)不殆,只有對(duì)黑客的注入手法充分了解,才可以有針對(duì)性的采取防御措施。
下面就針對(duì)實(shí)際的例子,對(duì)黑客的攻擊手法進(jìn)行抽絲剝繭的分析。例如對(duì)于某在線圖書(shū)銷售網(wǎng)站來(lái)說(shuō),在其PHP網(wǎng)頁(yè)開(kāi)發(fā)語(yǔ)言中存在“$con = " pg_connect("host=localhost dbname=newdb user=postgres password=xxx")"”語(yǔ)句,連接后臺(tái)的PostgreSQL數(shù)據(jù)庫(kù),使用“postgres”超級(jí)管理員,“xxx”為該賬戶密碼。
在后臺(tái)Ubuntu系統(tǒng)中執(zhí)行“su - postgres”命令,切換到“postgres”賬戶環(huán)境,執(zhí)行“psql”命令,在提示符下執(zhí)行“c newdb;”命令連接到數(shù)據(jù)庫(kù),在其中可以查詢各種表的內(nèi)容。在網(wǎng)站的查詢頁(yè)面中輸入作者的名稱,可以查詢到相關(guān)的書(shū)籍。在查詢頁(yè)面中存在“$sql= "SELECT * FROM Books WHERE uname ='$uname'ORDER BY id"”之類的語(yǔ)句,執(zhí)行搜索后,將符合條件的內(nèi)容顯示出來(lái)。
但是,這卻存在很嚴(yán)重的安全問(wèn)題。如果黑客在地址欄的提交語(yǔ)句后面添加某些內(nèi)容,發(fā)起注入攻擊,雖然該語(yǔ)句會(huì)出現(xiàn)執(zhí)行錯(cuò)誤的提示,但會(huì)讓黑客非法查詢到數(shù)據(jù)庫(kù)中的用戶表的內(nèi)容,將敏感賬戶名稱和密碼顯示出來(lái),用戶表中的信息用于網(wǎng)站認(rèn)證之用。
該非法注入語(yǔ)句中有“'”符號(hào),實(shí)現(xiàn)了針對(duì)原查詢語(yǔ)句的閉合作用,并使用后面的“and”語(yǔ)句連接非法的查詢語(yǔ)句。而查詢語(yǔ)句針對(duì)用戶表中的賬戶ID和密碼進(jìn)行搜索,并將兩者連接在一起返回,并故意使用轉(zhuǎn)換函數(shù)進(jìn)行錯(cuò)誤操作,讓網(wǎng)頁(yè)出現(xiàn)報(bào)錯(cuò)提示,這樣在頁(yè)面上就會(huì)顯示非法查詢的內(nèi)容了。
當(dāng)然,狡猾的黑客為避開(kāi)禁止顯示錯(cuò)誤信息的限制,會(huì)使用聯(lián)合查詢方式進(jìn)行滲透。例如其可以將上述非法查詢語(yǔ)句進(jìn)行修改,直接將當(dāng)前的表和用戶表的相關(guān)內(nèi)容拼接在一起顯示。
在網(wǎng)站的登錄界面,要求輸入正確的賬戶名和密碼才可以通過(guò)認(rèn)證。在認(rèn)證頁(yè)面中存在諸如“
例如,黑客可以在認(rèn)證頁(yè)面中輸入任何賬戶名,在密碼欄中輸入特殊格式字符串,就可以繞開(kāi)認(rèn)證文件,這是因?yàn)樵谏鲜鯯QL語(yǔ)句的尾部添加了特殊字符串,讓W(xué)here語(yǔ)句始終處于成立狀態(tài)的緣故。因此說(shuō),只要登錄頁(yè)面存在SQL注入漏洞,就可能讓密碼輸入形同虛設(shè)。利用SQL注入攻擊,黑客不僅可以非法查看數(shù)據(jù),繞開(kāi)認(rèn)證環(huán)節(jié),甚至可以對(duì)數(shù)據(jù)進(jìn)行非法修改。
實(shí)際上,不同網(wǎng)站采用的數(shù)據(jù)庫(kù)引擎是不同的,黑客會(huì)有針對(duì)性的采取不同手法的SQL注入攻擊,來(lái)達(dá)到諸如執(zhí)行系統(tǒng)命令、讀取文件、編輯文件、利用HTTP請(qǐng)求攻擊別的服務(wù)器等目的。
根據(jù)以上分析,可以看到SQL注入攻擊之所以可以實(shí)現(xiàn),在很大程度上是因?yàn)樽置媪康脑颍诳屯ㄟ^(guò)開(kāi)發(fā)者意想不到的方式(例如單引號(hào)閉合、聯(lián)合查詢、利用分號(hào)執(zhí)行下一語(yǔ)句等)來(lái)改變SQL語(yǔ)句的構(gòu)造,實(shí)現(xiàn)對(duì)網(wǎng)站的攻擊行為。
所謂字面量,指的是SQL語(yǔ)句中的固定值,SQL語(yǔ)句中的每種數(shù)據(jù)類型都用對(duì)應(yīng)的字面量,最常用是字符串和數(shù)值字面量。
對(duì)于SQL標(biāo)準(zhǔn)規(guī)格來(lái)說(shuō),字符串字面量必須以單引號(hào)括起來(lái),如果要在字符串字面量?jī)?nèi)使用單引號(hào),就需要使用連續(xù)兩個(gè)單引號(hào)來(lái)表示,這被稱為單引號(hào)轉(zhuǎn)義。
例 如 將“C'Apple”用于SQL字符串字面量時(shí)必須更改為“C''Apple”。但是在存在SQL注入漏洞的程序中,由于沒(méi)有轉(zhuǎn)義單引號(hào),就會(huì)導(dǎo)致出諸如“select * from tb1 where name='C'Apply'”之類的語(yǔ)句。導(dǎo)致“'C'Apply'”字符串中間的單引號(hào)造成閉合現(xiàn)象,后面的“Apply'”被排斥在字符串字面量之外,造成該部分沒(méi)有任何意義,不可避免的會(huì)產(chǎn)生語(yǔ)法錯(cuò)誤。
但是,如果將上述“Apply'”替換為有意義的SQL語(yǔ)句,就會(huì)導(dǎo)致SQL注入攻擊的發(fā)生,這才是SQL攻擊之所以存在的根本原因。
因?yàn)樵赟QL注入攻擊中,對(duì)于被插入的單引號(hào)排除出的字符串來(lái)說(shuō),其實(shí)是有意義的SQL語(yǔ)句,就會(huì)被應(yīng)用程序調(diào)用而觸發(fā)特定的操作(例如篡改數(shù)據(jù)等)。
因此,無(wú)論SQL注入攻擊如何厲害,只要其被解釋為字面量就沒(méi)有任何問(wèn)題,反之就會(huì)就會(huì)讓黑客攻擊得手。
除了針對(duì)字符串字面量的攻擊外,數(shù)值字面量也會(huì)遭到SQL注入攻擊的威脅。在網(wǎng)頁(yè)程序中,經(jīng)常會(huì)使用到ASP、PHP等動(dòng)態(tài)類型語(yǔ)言,其特點(diǎn)是不會(huì)限制變量的類型。這就會(huì)導(dǎo)致應(yīng)該輸入數(shù)值的位置可能會(huì)被輸入其他類型的字符的情況,就會(huì)形成SQL注入攻擊。
例 如 對(duì) 于“select *from employee where age< $age”語(yǔ)句來(lái)說(shuō),如果將“15;delete from tb1” 這一字符串傳進(jìn)來(lái),就會(huì)被錯(cuò)誤執(zhí)行造成數(shù)據(jù)被刪除的問(wèn)題。
因?yàn)閿?shù)字字面量沒(méi)有被單引號(hào)括起來(lái),所以當(dāng)出現(xiàn)非數(shù)值的字符串時(shí),就會(huì)被視為數(shù)字字面量終止,上述傳入的字符串中的分號(hào)之后的內(nèi)容就被排除在數(shù)值字面量之外,被解釋為SQL語(yǔ)句的一部分。
因此,產(chǎn)生SQL注入漏洞的根本原因,是在于被指定為參數(shù)的字符串的一部分被排除在字面量之外,從而造成SQL語(yǔ)句發(fā)生了變化的緣故。
根據(jù)以上分析,要想有效防御SQL注入漏洞,必須防止SQL語(yǔ)句在拼接過(guò)程中被惡意更改。
解決的方法包括使用占位符(Place Holder)拼接SQL語(yǔ)句,以及在應(yīng)用程序拼接SQL語(yǔ)句時(shí),確保字面量被正確處理,保證SQL語(yǔ)句不被惡意更改。SQL語(yǔ)句中的問(wèn)號(hào)就是占位符,表示將變量或者表達(dá)式等可變參數(shù)填到此處。對(duì)于實(shí)際的安全防御中,最常用的是前一種方式。
例如對(duì)于上述網(wǎng)站來(lái)說(shuō),可以在網(wǎng)頁(yè)中對(duì)語(yǔ)句進(jìn)行修改,將其變?yōu)椋骸?uname = $_GET['uname'];
$m d b 2 = M D B 2::connect('pgsq l://bookuser:bookuser@localhost/bookdb?charset=utf8');
$sql = "SELECT * FROM books WHERE uname = ?ORDER BY id"
$stmt = $mdb2 ->prepare($s q l,array('text'));
rs = $stmt->execute(array($uname));
不再使用權(quán)限極大的數(shù)據(jù)庫(kù)管理員賬戶,改用權(quán)限較小的賬戶來(lái)連接數(shù)據(jù)庫(kù),當(dāng)然該賬戶擁有對(duì)該數(shù)據(jù)庫(kù)的合理訪問(wèn)權(quán)限。
在上述語(yǔ)句中使用了“?”占 位 符,在 使 用“execute”方法調(diào)用時(shí),指定了實(shí)際的參數(shù)值和類型(這里為“text”類型),將值分配給給占位符這一操作被稱為綁定變量。
這里的“array('text')”表示占位符中的實(shí)際數(shù) 據(jù)。“rs = $stmt->execute(array($author));”語(yǔ)句表示提取用戶填入的的數(shù)據(jù)到變量中。通過(guò)占位符,讓數(shù)據(jù)庫(kù)按照指定的格式來(lái)進(jìn)行預(yù)先編譯,得到執(zhí)行的數(shù)據(jù)結(jié)構(gòu),該結(jié)構(gòu)是不可改變的。然后等待需要傳入的實(shí)際數(shù)據(jù),最后執(zhí)行實(shí)際的語(yǔ)句,得到執(zhí)行結(jié)果數(shù)據(jù)。
綜上所述,靜態(tài)占位符綁定變量的操作在數(shù)據(jù)庫(kù)引擎中執(zhí)行,包含占位符的語(yǔ)句被直接發(fā)送給數(shù)據(jù)庫(kù)引擎,數(shù)據(jù)庫(kù)引擎對(duì)其進(jìn)行編譯后確定SQL語(yǔ)句結(jié)構(gòu),隨后綁定的數(shù)據(jù)被發(fā)送給數(shù)據(jù)庫(kù)引擎,數(shù)據(jù)庫(kù)引擎得到數(shù)據(jù)庫(kù)將其填入到SQL語(yǔ)句并執(zhí)行。因?yàn)镾QL語(yǔ)句是在包含占位符的狀態(tài)下被編譯的,所以其是不可再次被更改的。
除了使用靜態(tài)占位符防御SQL注入攻擊外,還可以使用動(dòng)態(tài)占位符來(lái)應(yīng)對(duì)威脅。
動(dòng)態(tài)占位符的工作方式為先在處理SQL的程序庫(kù)中執(zhí)行綁定變量操作,之后將SQL語(yǔ)句發(fā)送給數(shù)據(jù)庫(kù)引擎加以處理,在綁定變量時(shí)字面量會(huì)被正確處理,這可以有效防御SQL注入攻擊。
不管是靜態(tài)占位符,還是動(dòng)態(tài)占位符,都可以有效消除SQL注入漏洞,兩者比較后可以發(fā)現(xiàn),靜態(tài)占位符可以徹底解除SQL注入的威脅,所以應(yīng)該盡可能在實(shí)際的工作中采用靜態(tài)占位符的方式。
除了使用靜態(tài)靜態(tài)占位符這一根本性的解決方式外,還可以使用一些輔助性的技術(shù)來(lái)防范SQL注入攻擊。如禁止頁(yè)面顯示錯(cuò)誤信息,對(duì)輸入的數(shù)據(jù)進(jìn)行校驗(yàn),設(shè)置合理的數(shù)據(jù)庫(kù)權(quán)限等。
例如,黑客會(huì)利用錯(cuò)誤信息頁(yè)面來(lái)查看SQL注入攻擊后的得到的數(shù)據(jù),為了避免顯示詳細(xì)的錯(cuò)誤信息,可以在PHP配置文件中輸入“display_errors = off”行,關(guān)閉錯(cuò)誤信息顯示功能,讓黑客無(wú)法通過(guò)錯(cuò)誤頁(yè)面獲取敏感信息。
對(duì)用戶輸入的內(nèi)容進(jìn)行檢測(cè),也可以有效避免SQL注入攻擊危害,如根據(jù)應(yīng)用程序的規(guī)格檢驗(yàn)輸入值,清除惡意輸入的數(shù)據(jù)等。
例如對(duì)于身份證來(lái)說(shuō),可以利 用“^d{15}|d{18}$”之類的正則表達(dá)式加以校驗(yàn)。將Web應(yīng)用數(shù)據(jù)庫(kù)的訪問(wèn)權(quán)限進(jìn)行合理的數(shù)值,例如不要使用權(quán)限很大的管理員賬戶,盡量使用最低權(quán)限的賬戶,這樣即使發(fā)生了SQL注入攻擊,也可以將損失降低到最小。
對(duì)于僅僅需要顯示普通信息的操作,只要開(kāi)放對(duì)應(yīng)數(shù)據(jù)表的讀取權(quán)限即可,而不要賦予其寫(xiě)入權(quán)限,就可以避免數(shù)據(jù)被惡意篡改。
對(duì)數(shù)據(jù)庫(kù)管理員的權(quán)限進(jìn)行適當(dāng)?shù)南拗?,可以避免黑客通過(guò)SQL注入攻擊來(lái)非法讀取文件,將其對(duì)系統(tǒng)的危害降到最低。