SQL攻擊與PreparedStatement
阿新 • • 發佈:2018-11-10
1.什麼是SQL攻擊。
在需要使用者輸入的地方,使用者輸入的是SQL語句的片段,終端使用者輸入的SQL片段與我們DAO中寫的SQL語句合成一個完整的SQL語句!例如使用者在輸入使用者名稱以及登陸密碼都是SQL語句時,我們的程式就會將其嵌入到我們的SQL語句中,最終可能出現數據庫的錯誤。
2.PreparedStatement
1)它是Statement介面的子介面;
2)強大之處
2.1)防SQL攻擊。
2.2)提高程式碼的可讀性。
2.3) 提高效率
例項:
public boolean login(String username,String password) throws Exception{ ResultSet re = null; Connection con = null; Statement stmt = null; String sql = "select * from users where Id = '" +username+"' and Password = '"+password+"'"; boolean result = false; try{ //設定四大引數 String driverClassName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/timebookstore"; String sqlUserName = "***"; String sqlPassword = "123456"; //載入類 Class.forName(driverClassName); //連線資料庫獲取Connection物件 con = DriverManager .getConnection(url,sqlUserName,sqlPassword); //獲取Statement,用於向資料庫傳送SQL語句 stmt = con.createStatement(); //傳送查詢語句 re=stmt.executeQuery(sql); result = re.next(); }catch(Exception e){ e.printStackTrace(); }finally{ if(re != null)re.close(); if(stmt != null)stmt.close(); if(con != null)con.close(); } return result; } @Test public void fun2() throws Exception{ String username = "abc"; String password = "123"; System.out.println(login(username,password)); }
控制檯輸出的結果是false,表示驗證不成功。但是如果使用者名稱和密碼改為如下:
@Test
public void fun2() throws Exception{
String username = "abc' or 'a' = 'a";
String password = "123' or 'a' = 'a";
System.out.println(login(username,password));
}
也即完整的sql語句為:
select * from users where Id = 'abc' or 'a' = 'a' and Password = '123' or 'a' = 'a'
很明顯這一句查詢語句返回表中的所有內容,所以結果是true。這就是sql攻擊.
下面的例子使用PreparedStatement防止sql攻擊。
public boolean login(String username,String password) throws Exception{ ResultSet re = null; Connection con = null; PreparedStatement pstmt = null; String sql = "select * from users where Id = ? and password = ?"; boolean result = false; try{ //設定四大引數 String driverClassName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/timebookstore"; String sqlUserName = "***"; String sqlPassword = "123456"; //載入類 Class.forName(driverClassName); //連線資料庫獲取Connection物件 con = DriverManager .getConnection(url,sqlUserName,sqlPassword); //獲取PreparedStatement,用於向資料庫傳送SQL語句 pstmt = con.prepareStatement(sql); //設定sql的引數 pstmt.setString(1, username); pstmt.setString(2,password); //執行sql語句 re=pstmt.executeQuery(); result = re.next(); }catch(Exception e){ e.printStackTrace(); }finally{ if(re != null)re.close(); if(pstmt != null)pstmt.close(); if(con != null)con.close(); } return result; } @Test public void fun2() throws Exception{ String username = "abc' or 'a' = 'a"; String password = "123' or 'a' = 'a"; System.out.println(login(username,password)); }
使用PreparedStatement的結果是false,與我們預期的一樣了。
由上面的例子可以看出使用PreparedStatement,編寫的sql語句更加直觀,還可以防sql攻擊。
String sql = "select * from users where Id = '"+username+"' and password = '"+password+"'";//Statement
String sql = "select * from users where Id = ? and password = ?";//PreparedStatement
?號表示引數,下面有設定該引數的程式碼。
pstmt = con.prepareStatement(sql);
//設定sql的引數
pstmt.setString(1, username);
pstmt.setString(2,password);