sql注入式錯誤(SQL injection)
SQL Injection 就是利用某些數據庫的外部接口將用戶數據插入到實際的數據庫操作語言(SQL)當中,從而達到入侵數據庫乃至操作系統的目的。它的產生主要是由於程序對用戶輸入的數據沒有進行嚴格的過濾,導致非法數據庫查詢語句的執行。
《深入淺出 MySQL》
危害
攻擊者利用它來讀取、修改或者刪除數據庫內的數據,獲得數據庫中用戶資料和密碼等信息,更嚴重的就是獲得管理員的權限。
例子
//注入式錯誤
public static void test3(String name,String passward){
Connection connection = null;
Statement st = null;
ResultSet rs = null;
try {
// 加載JDBC 驅動
Class.forName("com.mysql.jdbc.Driver");
// 獲得JDBC 連接
String url = "jdbc:mysql://localhost:3306/tulun";
connection = DriverManager.getConnection(url,"root","123456");
//創建一個查詢語句
st = connection.createStatement();
//sql語句
String sql = "select * from student where name = '"+ name+"' and passward = '"+passward+"'";
rs = st.executeQuery(sql);
if(rs.next()){
System.out.println("登錄成功。");
}else{
System.out.println("登錄失敗。");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
test3("wjm3' or '1 = 1","151515");
}
數據庫信息
如上面的代碼所示,用戶名爲wjm3’ or '1 = 1,密碼爲151515,從數據庫中可以看出我們沒有這樣的用戶,本來應該顯示登錄失敗,但是結果卻是登陸成功,因爲or '1 = 1 已經不是用戶名裏面的內容了,它現在爲SQL 語句裏面的內容,不論如何,結果都爲true,等於不用輸密碼都可以登錄。這裏就產生了安全問題。
解決方法
1. PrepareStatement
//注入式錯誤
public static void test3(String name,String passward){
Connection connection = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
// 加載JDBC 驅動
Class.forName("com.mysql.jdbc.Driver");
// 獲得JDBC 連接
String url = "jdbc:mysql://localhost:3306/tulun";
connection = DriverManager.getConnection(url,"root","123456");
//創建一個查詢語句
String sql1 = "select * from student where name = ? and passward = ?";
st = connection.prepareStatement(sql1);
st.setString(1,name);
st.setString(2,passward);
//sql語句
//String sql = "select * from student where name = '"+ name+"' and passward = '"+passward+"'";
rs = st.executeQuery();
if(rs.next()){
System.out.println("登錄成功。");
}else{
System.out.println("登錄失敗。");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
connection.close();
st.close();
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
test3("wjm3' or '1 = 1","151515");
}
上面這個代碼不管name 參數是什麼,它都只是name 參數,不會作爲sql語句的一部分來執行,一般來說推薦這個方法,比較安全。
2.自己定義函數進行校驗
- 整理數據使之變得有效
- 拒絕已知的非法輸入
- 只接受已知的合法輸入
所以如果想要獲得最好的安全狀態,目前最好的解決辦法就是對用戶提交或者可能改變的數據進行簡單分類,分別應用正則表達式來對用戶提供的輸入數據進行嚴格的檢測和驗證。
其實只需要過濾非法的符號組合就可以阻止已知形式的攻擊,並且如果發現更新的攻擊符號組合,也可以將這些符號組合增添進來,繼續防範新的攻擊。特別是空格符號和其產生相同作用的分隔關鍵字的符號,例如“/**/”,如果能成功過濾這種符號,那麼有很多注入攻擊將不能發生,並且同時也要過濾它們的十六進制表示“%XX”。