什么是SQL 指令植入式攻擊?
在設(shè)計(jì)或者維護(hù)Web 網(wǎng)站時(shí),你也許擔(dān)心它們會(huì)受到某些卑鄙用戶的惡意攻擊。的確,如今的 Web 網(wǎng)站開發(fā)者們針對(duì)其站點(diǎn)所在操作系統(tǒng)平臺(tái)或Web 服務(wù)器的安全性而展開的討論實(shí)在太多了。不錯(cuò),IIS 服務(wù)器的安全漏洞可能招致惡意攻擊;但你的安全檢查清單不應(yīng)該僅僅有 IIS 安全性這一條。有些代碼,它們通常是專門為數(shù)據(jù)驅(qū)動(dòng)(data-driven) 的 Web 網(wǎng)站而設(shè)計(jì)的,實(shí)際上往往同其它 IIS 漏洞一樣存在嚴(yán)重的安全隱患。這些潛伏于代碼中的安全隱患就有可能被稱為“SQL 指令植入式攻擊” (SQL injection) 的手段所利用而導(dǎo)致服務(wù)器受到攻擊。
SQL 指令植入式攻擊技術(shù)使得攻擊者能夠利用 Web 應(yīng)用程序中某些疏于防范的輸入機(jī)會(huì)動(dòng)態(tài)生成特殊的 SQL 指令語句。舉一個(gè)常見的例子:
某Web 網(wǎng)站采用表單來收集訪問者的用戶名和密碼以確認(rèn)他有足夠權(quán)限訪問某些保密信息,然后該表單被發(fā)送到 Web 服務(wù)器進(jìn)行處理。接下來,服務(wù)器端的ASP 腳本根據(jù)表單提供的信息生成 SQL 指令語句提交到 SQL 服務(wù)器,并通過分析SQL 服務(wù)器的返回結(jié)果來判斷該用戶名/密碼組合是否有效。
為了實(shí)現(xiàn)這樣的功能,Web 程序員可能會(huì)設(shè)計(jì)兩個(gè)頁面:一個(gè) HTML 頁面 (Login.htm) 用于登錄,另一個(gè)ASP 頁面 (ExecLogin.asp) 用于驗(yàn)證用戶權(quán)限(即向數(shù)據(jù)庫查詢用戶名/密碼組合是否存在)。具體代碼可能象這樣:
Login.htm (HTML 頁面)
代碼:<form action="ExecLogin.asp" method="post"> Username: <input type="text" name="txtUsername"><br> Password: <input type="password" name="txtPassword"><br> <input type="submit"> </form>
ExecLogin.asp (ASP 頁面) 代碼:<% Dim p_strUsername, p_strPassword, objRS, strSQL p_strUsername = Request.Form("txtUsername") p_strPassword = Request.Form("txtPassword") strSQL = "SELECT * FROM tblUsers " & _ "WHERE Username=" & p_strUsername & _ " and Password=" & p_strPassword & "" Set objRS = Server.CreateObject("ADODB.Recordset") objRS.Open strSQL, "DSN=..." If (objRS.EOF) Then Response.Write "Invalid login." Else Response.Write "You are logged in as " & objRS("Username") End If Set objRS = Nothing %>
乍一看,ExecLogin.asp 的代碼似乎沒有任何安全漏洞,因?yàn)橛脩羧绻唤o出有效的用戶名/密碼組合就無法登錄。然而,這段代碼偏偏不安全,而且它正是SQL 指令植入式攻擊的理想目標(biāo)。具體而言,設(shè)計(jì)者把用戶的輸入直接用于構(gòu)建SQL 指令,從而使攻擊者能夠自行決定即將被執(zhí)行的 SQL 指令。例如:攻擊者可能會(huì)在表單的用戶名或密碼欄中輸入包含“ or ”和“=” 等特殊字符。于是,提交給數(shù)據(jù)庫的 SQL 指令就可能是: 代碼:SELECT * FROM tblUsers WHERE Username= or = and Password = or =
這樣,SQL 服務(wù)器將返回 tblUsers 表格中的所有記錄,而 ASP 腳本將會(huì)因此而誤認(rèn)為攻擊者的輸入符合 tblUsers 表格中的第一條記錄,從而允許攻擊者以該用戶的名義登入網(wǎng)站。
SQL 指令植入式攻擊還有另一種形式,它發(fā)生在 ASP 服務(wù)器根據(jù) querystring 參數(shù)動(dòng)態(tài)生成網(wǎng)頁時(shí)。這里有一個(gè)例子,此 ASP 頁面從 URL 中提取出 querystring 參數(shù)中的 ID 值,然后根據(jù) ID 值動(dòng)態(tài)生成后繼頁面: 代碼:<% Dim p_lngID, objRS, strSQL p_lngID = Request("ID") strSQL = "SELECT * FROM tblArticles WHERE ID=" & p_lngID Set objRS = Server.CreateObject("ADODB.Recordset") objRS.Open strSQL, "DSN=..." If (Not objRS.EOF) Then Response.Write objRS("ArticleContent") Set objRS = Nothing %>
在一般情況下,此 ASP 腳本能夠顯示具有特定 ID 值的文章的內(nèi)容,而 ID 值是由 URL 中的 querystring 參數(shù)指定的。例如:當(dāng)URL為http://www.example.com/Article.asp?ID=1055 時(shí),ASP 就會(huì)根據(jù) ID 為 1055 的文章提供的內(nèi)容生成頁面。
如同前述登錄頁面的例子一樣,此段代碼也向SQL 指令植入式攻擊敞開了大門。某些惡意用戶可能會(huì)把 querystring 中的文章 ID 值偷換為“0 or 1=1”等內(nèi)容(也就是說,把 URL 換成http://www.example.com/Article.asp?ID=0 or 1=1) 從而誘使 ASP 腳本生成不安全的 SQL 指令如: 代碼:SELECT * FROM tblArticles WHERE ID=0 or 1=1
于是,數(shù)據(jù)庫將會(huì)返回所有文章的內(nèi)容。
當(dāng)然了,本例服務(wù)器所受的攻擊不一定會(huì)引起什么嚴(yán)重后果。可是,攻擊者卻可能變本加厲,比如用同樣的手段發(fā)送 DELETE 等 SQL 指令。這只需要簡單地修改前述 URL 中的 querystring 參數(shù)就可以了!例如:任何人都可以通過 http://www.example.com/Article.asp?ID=1055; DELETE FROM tblArticles ” 之類的 URL 來訪問 Web 網(wǎng)站。
SQL 指令植入式攻擊的危害
SQL 指令植入式攻擊可能引起的危害取決于該網(wǎng)站的軟件環(huán)境和配置。當(dāng) Web 服務(wù)器以操作員(dbo)的身份訪問數(shù)據(jù)庫時(shí),利用SQL 指令植入式攻擊就可能刪除所有表格、創(chuàng)建新表格,等等。當(dāng)服務(wù)器以超級(jí)用戶 (sa) 的身份訪問數(shù)據(jù)庫時(shí),利用SQL 指令植入式攻擊就可能控制整個(gè) SQL 服務(wù)器;在某些配置下攻擊者甚至可以自行創(chuàng)建用戶帳號(hào)以完全操縱數(shù)據(jù)庫所在的 Windows 服務(wù)器。
杜絕SQL 指令植入式攻擊
杜絕SQL 指令植入式攻擊的第一步就是采用各種安全手段監(jiān)控來自 ASP request 對(duì)象 (Request 、 Request.QueryString 、 Request.Form 、 Request.Cookies 和 Request.ServerVariables) 的用戶輸入,以確保 SQL 指令的可靠性。具體的安全手段根據(jù)你的 DBMS 而異,下面給出的都是基于 MS SQL Server的例子。
在前述登錄頁面的例子中,腳本期望得到的兩個(gè)輸入變量 (txtUserName 和 txtPassword)均為字符串類型。無論用戶在哪個(gè)參數(shù)中插入單引號(hào),他都可能讓數(shù)據(jù)庫執(zhí)行單引號(hào)中的 SQL 指令。為了杜絕此類SQL 指令植入式攻擊,我們可以借助 Replace 函數(shù)剔除單引號(hào),比如:
代碼:p_strUsername = Replace(Request.Form("txtUsername"), "", "") p_strPassword = Replace(Request.Form("txtPassword"), "", "")
在第二個(gè)例子中,腳本期望的輸入變量是長整型變量 (ID) 。用戶可以通過在 ID 參數(shù)中插入特殊字符來運(yùn)行不安全的 SQL 指令。為了為了杜絕此類SQL 指令植入式攻擊,我們只需要借助 CLng 函數(shù)限制 ID 值為長整型變量,比如: 代碼:p_lngID = CLng(Request("ID"))
當(dāng)用戶試圖在 ID 中包含特殊字符時(shí),CLng 就會(huì)產(chǎn)生一個(gè)錯(cuò)誤。
為了進(jìn)一步減少SQL 指令植入式攻擊的危脅,請(qǐng)務(wù)必清除客戶端錯(cuò)誤信息文本中的所有技術(shù)資料。某些錯(cuò)誤信息往往泄露了技術(shù)細(xì)節(jié),從而讓攻擊者可以看出服務(wù)器的安全漏洞所在。這里指的錯(cuò)誤信息不但包括應(yīng)用程序生成的消息框,還包括來自 IIS 的出錯(cuò)提示。為此,你可以禁止由 IIS 發(fā)送的詳細(xì)錯(cuò)誤信息,而改用自定義的出錯(cuò)頁面。(關(guān)于創(chuàng)建自定義的出錯(cuò)頁面的更多信息,請(qǐng)務(wù)必參閱 《Creating Custom ASP Error Pages》。)
最后,為了減輕SQL 指令植入式攻擊的危害,請(qǐng)限制 Web 應(yīng)用程序所用的數(shù)據(jù)庫訪問帳號(hào)權(quán)限。一般來說,應(yīng)用程序沒有必要以 dbo 或者 sa 的身份訪問數(shù)據(jù)庫。記住,給它的權(quán)限越少,你的網(wǎng)站越安全!你還可以考慮分別給每個(gè)需要訪問數(shù)據(jù)庫的對(duì)象分配只擁有必需權(quán)限的帳號(hào),以分散安全漏洞。例如:同是前端用戶界面,當(dāng)用于公共場所時(shí)就比用于具有本地內(nèi)容管理機(jī)制的平臺(tái)時(shí)更加需要嚴(yán)格限制數(shù)據(jù)庫訪問權(quán)限。