作者:肖文偉
今天在IBM的站點上看到一篇關(guān)于系統(tǒng)安全的文章,文章是由伍斯特工業(yè)學(xué)院(Worcester Polytechnic Institute,WPI)的計算機科學(xué)在讀研究生Bob Breznak寫的.
中間有很多關(guān)于系統(tǒng)攻擊方法,不禁讓人深思:我們的系統(tǒng)到底有多脆弱呢?
文章位于:
http://www.ibm.com/developerworks/cn/rational/edge/08/may08/breznak/
我嘗試了文中所講的利用SQL注入的這種簡單的攻擊方法,以及我所知道的解決方法,我將它分享出來,希望你看過之后會有所收獲.當然,我指的有所收獲不是讓你嘗試去攻擊別人的系統(tǒng),而是讓你在設(shè)計系統(tǒng)的時候也將這類安全問題考慮進去.
首先讓我們來看看我們在JAVA中常用到的驗證用戶登錄的SQL語句:
String sql="SELECT * FROM users WHERE Login_name='"+username+"' and Password='"+password+"'";
假設(shè)我的數(shù)據(jù)表users中有這樣一些數(shù)據(jù):
Login_name
|
Password
|
admin
|
abc#@4531
|
xiaowenwei
|
#@#Measuer71
|
1. 當用戶在登錄時輸入:Login_name= "admin"; Password= "abc#@4531"時我們的SQL語句會變成:
String sql="SELECT * FROM users WHERE Login_name='admin' and Password=' abc#@4531'";
這樣可以查看出來一條結(jié)果,系統(tǒng)也不會有問題,一切正常.
Ok,讓我們再來看看下面的這種方式.
2. 當黑客在登錄時輸入:Login_name= "admin"; Password= "def' OR 1=1--"時我們的SQL語句會變成:(注意,用戶輸入法的Password字符串是: "def' OR 1=1--")
String sql="SELECT * FROM users WHERE Login_name='admin' and Password='def' OR 1=1-—'";
看出來什么了嗎?
這句SQL會這樣執(zhí)行:
SELECT * FROM users WHERE Login_name='admin' and Password='def' OR 1=1
后面的-—'被當作SQL注釋了.
這樣結(jié)果我們可想而知,黑客不用知道密碼便輕易登錄上你的系統(tǒng)了,這樣他便可以利用SQL注入在你的系統(tǒng)上做更多讓你意想不到和害怕的事情!!!
解決方法(一):使用預(yù)處理器PreparedStatement
我嘗試了如果系統(tǒng)中使用處理器Statement來執(zhí)行登錄驗證的SQL語句的話,那你的系統(tǒng)就等著被黑吧.結(jié)果就會像上面所說的那樣.黑客可以輕易登錄上你的系統(tǒng).
而我嘗試將處理器改為預(yù)處理器之后,就不會發(fā)生這種問題了,代碼如下:(下面代碼示例是等著被黑的那種,中間注釋了使用預(yù)處理器的方法),至于是為什么,還是你自己來想吧.
/**
* 根據(jù)用戶名和密碼查詢用戶資料
* @param username 用戶登錄名
* @param password 用戶密碼
* @return 用戶實體
*/
public UserBean getUserByPwd(String username,String password)
{
//聲明用戶實體
UserBean user=null;
//獲得數(shù)據(jù)庫連接對象
Connection conn=DBConnection.getConnection();
//使用 預(yù)處理器 的SQL語句
//String sql="select * from Sys_user where Login_name=? and Password=?";
//使用 處理器 的SQL語句
String sql="select * from Sys_user where Login_name='"+username+"' and Password='"+password+"'";
try
{
//使用 預(yù)處理器 的方式:
/*PreparedStatement pstmt=conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs=pstmt.executeQuery();*/
//使用 處理器 的方式:
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(sql);
//如果有結(jié)果集
if(rs.next())
{
//獲得結(jié)果集中的結(jié)果
long userid=rs.getLong("User_id");
String loginname=rs.getString("Login_name");
String pwd=rs.getString("Password");
String uname=rs.getString("User_name");
short gender=rs.getShort("Gender");
String privatephone=rs.getString("Private_phone");
String companyphone=rs.getString("Company_phone");
String email=rs.getString("Email");
short isactive=rs.getShort("Is_active");
//將結(jié)果構(gòu)造成用戶實體
user=new UserBean(userid,loginname,pwd,uname,gender,privatephone,companyphone,email,isactive);
}
} catch (SQLException e)
{
e.printStackTrace();
}
//返回用戶實體
return user;
}
解決方法(二):對用戶密碼加密處理
這種方法比較可靠,我一般使用的是MD5加密方式,將用戶密碼加密成32位長度的16進制字符串.使用這種方式時,在系統(tǒng)中使用的過程一般為:
1. 注冊新用戶時,將用戶輸入的密碼進行MD5加密后再保存進數(shù)據(jù)庫;
2. 用戶修改密碼時,將用戶輸入的密碼進行MD5加密后再保存進數(shù)據(jù)庫;
3. 用戶登錄時,將用戶輸入的登錄密碼進行MD5加密后,再做SQL查詢;
我們可以寫一個專門用來將字符串進行MD5(或其它)加密的方法,在對密碼進行操作時先加密處理就可以了.(至于MD5加密的處理,我會在下一篇中貼出來,先申明這不是我寫的.)
這樣即使黑客在輸入密碼時是使用的"def' OR 1=1--"之類的字符串,我們也會先將它進行字符串加密處理成32位長度的字符串,然后再做SQL查詢.所以,這樣就能保證系統(tǒng)這部分始終是安全的.
我想可能有部分好鉆研的人,看到這會想到另一個問題.可能你也沒有想到.其實那個問題就是如果我輸入用戶名的時候使用"def' OR 1=1--"那會發(fā)生什么情況呢?
可想而知,那你也可以通過驗證,進入系統(tǒng)!
My god! 原來我們的系統(tǒng)是這么的不安全!是的,他就是這么的脆弱.
我想說的是,你最好是將解決方法(一)和解決方法(二)都使用起來,至少我是這么做的.
以上是我個人的見解,可能對于這部分你還有更好的方法,我希望能有機會和你一起來探討這方面的問題.或者其它關(guān)于開發(fā)的問題.如果我所說的有錯誤也希望你能批評指正出來,謝謝.