Java應用開發中的SQL注入攻擊


1. 什么是SQL注入攻擊?

SQL注入攻擊是黑客對數據庫進行攻擊的常用手段之一。隨着B/S模式應用開發的發展,使用這種模式編寫應用程序的程序員越來越多。但是由於程序員的水平及經驗參差不齊,相當一部分程序員在編寫代碼的時候,沒有對用戶輸入數據的合法性進行判斷,使應用程序存在安全隱患。用戶可以提交一段數據庫查詢代碼,根據程序返回的結果,獲得他想得知的數據,這就是所謂的SQL Injection.

SQL注入攻擊屬於數據庫安全攻擊手段之一,可以通過數據庫安全防護技術實現有效防護,數據庫安全防護技術包括數據庫漏掃,數據庫加密,數據庫防火牆,數據庫脫敏,數據庫安全審計系統。

SQL注入攻擊會導致的數據庫安全風險包括:刷庫,拖庫,撞庫。

 

2.基本思路

SQL注入是從正常的www端口訪問,而且表面看起來跟一般的頁面訪問沒什么區別,所以市面的防火牆都不會對SQL注入發出警報,如果管理員沒有查看日志的習慣,可能被入侵很長時間都不會發覺。SQL注入的手法相當靈活,在注入的時候會碰到很多意外的情況,需要構造巧妙的SQL語句,從而成功獲取想要的數據

1)發現SQL注入位置

2)判斷后台數據庫類型

3)確定XP_CMDSHELL可執行情況

4)發現WEB虛擬目錄

5)上傳木馬

6)得到管理員權限

 

3.舉個例子

 某個網站的登錄驗證的SQL查詢代碼為:strSQL = "SELECT * FROM users WHERE (name = '" + userName + "') and (pw = '"passWord +"');“

惡意填入
userName =  "1' OR '1'='1'";
passWord  "1' OR '1'='1" ;
時,將導致原本的SQL字符串被填為
strSQL =  "SELECT * FROM users WHERE (name = '1' OR '1'='1') and (pw = '1' OR '1'='1');"
也就是實際上運行的SQL命令會變成下面這樣的
strSQL =  "SELECT * FROM users;"
因此達到無賬號密碼,亦可登錄網站。所以SQL注入攻擊被俗稱為黑客的填空游戲。
 
 
4.怎么防范
 
查找與修補
一、注入點的查找
當我們想要測試某個站點時,一般會架上注入工具對其狂轟亂炸,這樣做雖然有時能找到注入點,但還是有些盲目,我個人的看法是:如果有源碼的話,就從源碼入手,在源碼中查找注入點。對於源碼,有些朋友可能覺得很難,其實源碼並不神秘,它也是有一定的語法規則的,看一套優秀的源碼就像是在欣賞一部精美的電影,只要我們堅持每天看一些優秀源碼,再加上百度這個老師的指點,用不了多久,源碼的神秘面紗就會被你揭去。閑話少說,下面我們就開始查找注入點,目標有兩個:一是Request,二是SQL語句。
說到Request,這個是ASP程序中的一個內建對象,怎么?不懂?那就跟我先來惡補一下吧!它是用來獲取客戶端信息的,有五種方法,而會出現注入點的一般有以下三種:
1、Request.QueryString:取得客戶端提交的信息。當Form以Get方法提交信息,或是直接在URL中提交變量值時,在服務器端接收數據時采用的就是這種方法。
2、Request.Form:同樣也是取得客戶端提交的信息,但它接收的是Form以Post方法提交的信息。
3、Request.Cookies:取得客戶端瀏覽器的Cookies信息。Cookies就是小甜餅,指的是一些私人信息,如用戶名、密碼之類的信息。
有些程序員為了減少錯誤,對於前兩種信息的獲取,會采用Request來取得客戶端提交的信息,這種方法,雖然可以通吃Request.QueryString和Request.Form的提交信息,但如果過濾的不好,就會被漏洞反咬一口。
了解過一些Request的知識后,下面就在“查找”中輸入“request”進行搜索,OK!當找到上面所列的三項Request語句后,再來看一下程序對這些Request語句是否做了過濾,比如ID值是否用INT過濾,例:id=int(request("id"));字符串值是否用replace ()或instr()等函數進行過濾單引號或一些特殊字符,例:username=replace(request("username"),"", "");或者程序是否采用本身的一些過濾函數來過濾這些提交值。從查找到這句request參數起,一直到SQL語句中使用這個提交值至,如果中間沒有上面的層層關卡,那么,一個注入點,基本上就算是出現了。
說到SQL語句,不能不提到以下幾個常用的語句:
1、查詢語句:Select [(<字段名1> [,<字段名2>, ...])] FROM <表名JMDCW> [Where <條件表達式> [AND|OR <條件表達式>...]
2、更新語句:Update <表名JMDCW> SET 列名1 = 常量表達式1[,列名2 = 常量表達式2 ...] Where <條件表達式> [AND|OR <條件表達式>...]
3、刪除語句:Delete FROM〈表名JMDCW〉[Where <條件表達式> [AND|OR <條件表達式>...]]
這里不對SQL語句做介紹了。在上面列出的SQL語句中,注入點出現頻率最高的是Select語句,而注入參數的出沒地通常都是在Where之后的條件中。當一個沒有過濾的Request語句進入SQL語句后,就是注入大顯身手的時候了,不過,在進行注入之前還要先看一下該參數是直接引入,還是用單引號引入的,另外,該參數是否還應用於其他SQL語句中,然后,根據不同的信息,選擇不同的處理方式,或直接暴破,或UNION查詢,當然,如果存在注入點的程序使用的是SQL數據庫,那就不單單是得到一些重要信息,甚至還可以增加管理員。
下面用“螞蟻影院3.0”版注銷用戶(wantlogin.asp)中的一段源碼來做一下介紹:
引用
<%
if request("userid1")<>"" then
set rst=server.createobject("adodb.recordset")
sql="select money,online from users where userid="&request("userid1")&" and password="&md5(request("pws"))&""
rst.open sql,conn,1,3
if rst.eof and rst.bof then
response.write"<script>alert(用戶名或密碼錯誤!);history.back();</Script>"
else
response.write"<script>alert(恢復成功你現在可以登陸!);</Script>"
response.write"<script Language=Javascript>location.href = index.asp;</script>"
rst.close
set rst=nothing
conn.close
set conn=nothing
end if
end if
%>
在其流程中,首先判斷取得的提交值userid1是否為空,不為空的話就進入SQL語句中,驗證取得的用戶名及密碼是否和數據庫內的用戶名及密碼一致,如果不一致,則彈出“用戶名及密碼錯誤”窗口,否則,就彈出“恢復成功”的窗口。這也是一段典型的注入漏洞源碼,並且,接收的方式還是使用的 request,這就給我們提交注入語句提供了最大的方便。如果我們在URL地址中提交如下字符:http: //127.0.0.1/wantlogin.asp?userid1=aa&pws=bb,因為沒有aa這個用戶,那么就會彈出錯誤窗口,而如果我們將aa換成如下字符:aa or 1=1 or 1=1,pws保持不變,這樣提交的語句到了SQL語句中就成了如下語句:
select money,online from users where userid1=aa or 1=1 or 1=1 and password=md5(bb),以往我們所見到的測試代碼一般為“or 1=1”,而這里卻多用了一個 or ,為什么要多用一個or呢?解釋一下,在邏輯運算符中,and的優先級別高於or ,程序運行后會先運算后面的1=1 and password=md5(bb),因為密碼是隨便輸入的,所以and后的password值為假,而and前的1=1雖然為真,但真and 假=假,所以,這個and的運算值為假,再來看or運算,因為前面的用戶名也是不存在的,其值當然為假,如此一來,where后的邏輯運算就成了如下表達式:假or真or假,結果值還是為真,這樣就會彈出“恢復成功”窗口,如果將其中的or 1=1 改為or 1=2,那邏輯表達式則成了:假or假or假,值當然也為假,彈出的就是“用戶名或密碼錯誤”的窗口。這樣,根據彈出窗口的不同,我們就可以構造一些特殊字符,然后猜測出需要的數據了,比如查詢管理員ID的語句,將or后的1=1更改為: 1=(Select top 1 id from admin),這里暫用admin表示管理員表名,如果存在ID為1的管理員,那么就會彈出“恢復成功”的窗口,否則,就證明管理員的ID不為1,那就要再用其他數字來測試。猜出管理員ID后,再把此段字符更改為猜測管理員名稱長度的字符:5<(Select len(adminname) from admin where id=1),如為真,則證明長度大於5,否則長度小於或等於5。猜出長度后,再用asc()函數來猜測管理員的名稱:90<(select asc(mid(adminname,1,1)) from admin where id=1),如此循環,就能暴破出管理員的名稱及密碼了。
上面提到的是Request.QueryString和Request.Form的注入方法,而Request.Cookies的注入方法則是要修改本地的Cookies值來實現的,推薦使用一些專門的Cookies修改工具,不過,用Cookies來注入相對而言,就麻煩了好多,但原理和前面的注入是一樣的,這里就不介紹了。
二、注入點的修補
在上面着重講了如何查找注入點及簡單的利用方法,當我們知道了攻后,也就明白了如何守,攻和守之間雖然是對立的,但也是相互的。明白了什么地方存在注入點,再來修補也就容易多了。在前面查找注入點時,我也提到查看程序中是否對提交參數進行了過濾,每個程序對注入的過濾函數都不相同,我們在修補自已站點上的注入點時,可參照其他程序中的過濾函數,也可根據自已的需要,單獨過濾一些敏感的字符。這里,還是以上面的那個例子來說一下如何修補注入點。在前面的 SQL語句中有這一句:userid="&request("userid1")&",這其中對提交來的參數是用單引號來引入的,而我們能成功注入也是在提交參數中加入了單引號來閉合其語句,這樣,加入一個replace()函數對單引號進行過濾,修改后的語句為:userid= "&replace(request("userid1"),"","")&",這樣用戶再提交帶有單引號的字符時, Replace()就會將單引號過濾為空,如此一來,提交的那些特殊字符也就失去了其意義。
當然,我們還可以在userid1進入SQL語句之前,對其長度進行一下判斷,如果超過規定的長度,就彈出錯誤,中止頁面執行並返回到指定的頁面。當然還可以借鑒一些優秀源碼中的過濾方法。總之,注入漏洞是可以避免的,即使出現了注入點,只要我們分析出其出現的原因,也就能很容易地將其修補了!
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM