一、SQL注入簡介
SQL注入是比較常見的網(wǎng)絡(luò)攻擊方式之一资昧,它不是利用操作系統(tǒng)的BUG來實現(xiàn)攻擊,而是針對程序員編程時的疏忽荆忍,通過SQL語句格带,實現(xiàn)無帳號登錄撤缴,甚至篡改數(shù)據(jù)庫。
二叽唱、SQL注入攻擊的總體思路
- 尋找到SQL注入的位置
- 判斷服務(wù)器類型和后臺數(shù)據(jù)庫類型
- 針對不通的服務(wù)器和數(shù)據(jù)庫特點進行SQL注入攻擊
三屈呕、SQL注入攻擊實例
比如在一個登錄界面,要求輸入用戶名和密碼:
可以這樣輸入實現(xiàn)免帳號登錄:
用戶名: ‘or 1 = 1 ––
密 碼:
點擊登錄尔觉,如果沒有做特殊處理凉袱,那么這個非法用戶就會很容易的登錄成功。(當(dāng)然現(xiàn)在的有些語言的數(shù)據(jù)庫API已經(jīng)處理了這些問題)
這是為什么呢侦铜?
從理論上說专甩,后臺認(rèn)證程序中會有如下的SQL語句:
String sql = "select * from user_table where username=
' "+userName+" ' and password=' "+password+" '";
當(dāng)輸入了上面的用戶名和密碼,上面的SQL語句變成:
select * from user_table where username=
'’or 1 = 1 -- and password='’
分析SQL語句:
條件后面username=”or 1=1 用戶名等于 ” 或1=1 那么這個條件一定會成功钉稍;然后后面加兩個-涤躲,這意味著注釋,它將后面的語句注釋贡未,讓它們不起作用种樱,這樣語句永遠(yuǎn)都能正確執(zhí)行,用戶輕易騙過系統(tǒng)俊卤,獲取合法身份嫩挤。這還是比較溫柔的,如果是執(zhí)行如下:
select * from user_table where
username=’’;DROP DATABASE (DB Name) --’ and password=’’
其后果可想而知消恍。
四岂昭、應(yīng)對方法
針對JSP,應(yīng)對方法如下:
1.(簡單又有效的方法)PreparedStatement
采用預(yù)編譯語句集狠怨,它內(nèi)置了處理SQL注入的能力约啊,只要使用它的setXXX方法傳值即可。
使用好處:
(1) 代碼的可讀性和可維護性佣赖;
(2) PreparedStatement盡最大可能提高性能恰矩;
(3) 最重要的一點是極大地提高了安全性。
原理:
sql注入只對sql語句的準(zhǔn)備(編譯)過程有破壞作用憎蛤。而PreparedStatement已經(jīng)準(zhǔn)備好了外傅,執(zhí)行階段只是把輸入串作為數(shù)據(jù)處理,而不再對sql語句進行解析俩檬、準(zhǔn)備栏豺,因此也就避免了sql注入問題。
2.使用正則表達(dá)式過濾傳入的參數(shù)
要引入的包:
import java.util.regex.*;
正則表達(dá)式:
private String CHECKSQL = “^(.+)\sand\s(.+)|(.+)\sor(.+)\s$”;
判斷是否匹配:
Pattern.matches(CHECKSQL,targerStr);
下面是具體的正則表達(dá)式:
檢測SQL meta-characters的正則表達(dá)式 :
/(%27)|(’)|(–)|(%23)|(#)/ix
修正檢測SQL meta-characters的正則表達(dá)式 :/((%3D)|(=))[^ ]*((%27)|(’)|(–)|(%3B)|(:))/i
典型的SQL 注入攻擊的正則表達(dá)式 :/w*((%27)|(’))((%6F)|o|(%4F))((%72)|r|(%52))/ix
檢測SQL注入豆胸,UNION查詢關(guān)鍵字的正則表達(dá)式 :/((%27)|(’))union/ix(%27)|(’)
檢測MS SQL Server SQL注入攻擊的正則表達(dá)式:
/exec(s|+)+(s|x)pw+/ix
等等奥洼。
3.字符串過濾
比較通用的一個方法:
(||之間的參數(shù)可以根據(jù)自己程序的需要添加)
public static boolean sql_inj(String str){
String inj_str = "’|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
String inj_stra[] = split(inj_str,"|");
for (int i=0 ; i < inj_stra.length ; i++ ){
if (str.indexOf(inj_stra[i])>=0){
return true;
}
}
return false;
}
4.jsp中調(diào)用該函數(shù)檢查是否包函非法字符
防止SQL從URL注入:
sql_inj.java代碼:
import [java.net](http://java.net/).*;
import [java.io](http://java.io/).*;
import java.sql.*;
import java.text.*;
import java.lang.String;
public class sql_inj{
public static boolean sql_inj(String str){
String inj_str = "’|and|exec|insert|select|delete|update|
count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
//這里的東西還可以自己添加
String[] inj_stra=inj_str.split("|");
for (int i=0 ; i < inj_stra.length ; i++ ){
if (str.indexOf(inj_stra[i])>=0){
return true;
}
}
return false;
}
}
5.JSP頁面判斷代碼:
使用javascript在客戶端進行不安全字符屏蔽
功能介紹:檢查是否含有”‘”,”\”,”/”
參數(shù)說明:要檢查的字符串
返回值:0:是1:不是
函數(shù)名是
function check(a){
return 1;
fibdn = new Array (”‘” ,”\”,”/”);
i=fibdn.length;
j=a.length;
for (ii=0; ii<i; ii++)
{ for (jj=0; jj<j; jj++)
{ temp1=a.charAt(jj);
temp2=fibdn[ii];
if (tem’; p1==temp2){
return 0;
}
}
}
return 1;
}
總的說來,防范一般的SQL注入只要在代碼規(guī)范上下點功夫就可以了晚胡。凡涉及到執(zhí)行的SQL中有變量時灵奖,用JDBC(或者其他數(shù)據(jù)持久層)提供的如:PreparedStatement就可以 嚼沿,切記不要用拼接字符串的方法就可以了。
五瓷患、降低注入攻擊的危害
- 把應(yīng)用服務(wù)器的數(shù)據(jù)庫權(quán)限降至最低骡尽,盡可能地減少 SQL 注入攻擊帶來的危害
- 避免網(wǎng)站打印出SQL錯誤信息,比如類型錯誤擅编、字段不匹配等攀细,把代碼里的SQL語句暴露出來,以防止攻擊者利用這些錯誤信息進行SQL注入爱态。
- 對進入數(shù)據(jù)庫的特殊字符('"\尖括號&*;等)進行轉(zhuǎn)義處理谭贪,或編碼轉(zhuǎn)換。
- 所有的查詢語句建議使用數(shù)據(jù)庫提供的參數(shù)化查詢接口锦担,參數(shù)化的語句使用參數(shù)而不是將用戶輸入變量嵌入到SQL語句中俭识,即不要直接拼接SQL語句。
- 在測試階段洞渔,建議使用專門的 SQL 注入檢測工具進行檢測套媚。網(wǎng)上有很多這方面的開源工具,例如sqlmap磁椒、SQLninja等堤瘤。
- 善用數(shù)據(jù)庫操作庫,有些庫包可能已經(jīng)做好了相關(guān)的防護浆熔,我們只需閱讀其文檔本辐,看是否支持相應(yīng)的功能即可。