Mysql 的sql注入是什麼?怎麼解決?
阿新 • • 發佈:2021-01-11
sql注入的原因
語句和使用者輸入的內容進行拼接,傳送給資料庫編譯的時候,資料庫將使用者輸入的內容當成sql語句編譯了。從而從根本上改變了我們開發者所期望sql語句原有的含義。導致程式受到sql攻擊。
sql注入的程式碼
這案例使用者名稱密碼均錯誤也可以登陸,就是發生了sql注入
public static void main(String[] args) throws Exception { //假設這裡的使用者名稱和密碼是前端頁面傳遞過來的。 String username = "admin' -- "; String password = "1234"; //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲取連線 Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/day05", "root", "123"); //建立statement物件 Statement statement = con.createStatement(); //向資料庫傳送sql語句,檢視該使用者是否存在。這條sql語句查詢的該使用者名稱和密碼的使用者有多少個。 String sql = "select count(*) from user where name = '" + username + "' and password = '" + password + "'"; ResultSet rs = statement.executeQuery(sql); int count = 0; while (rs.next()) { //獲取count(*)的值 count = rs.getInt(1); } if(count==1){ //只有一個同時滿足使用者名稱和密碼的使用者,可以登入 System.out.println("登入成功"); }else if(count==0){ //不存在該使用者 System.out.println("不能登入"); } }
執行程式碼,可以發現使用者名稱為 admin’ – ,密碼為 1234 這樣的使用者是不存在的,但是盡然可以登入成功。那麼這是什麼原因造成的呢?
將字串拼接後的sql語句放在視覺化工具中檢視發現如下情況,可以發現,後面密碼的驗證被註釋掉了。這樣豈不是誰都可以登入了?
解決方法
首先將sql語句所代表的含義確定下來,然後再向編譯好的sql語句中填充使用者輸入的內容。這樣使用者輸入的內容就不會再被編譯了。所以需要我們學習preparedStatement向資料庫傳送預編譯的sql語句。
就是preparedStatement + 佔位符 ?搭配使用(先編譯再傳引數)
解決sql注入之後的程式碼
public static void main(String[] args) throws Exception { String username = "wangwu' -- "; String password = "5555"; //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲取連線 Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/day09_1","root","123"); //建立preparedStatement物件 //要讓sql語句進行預編譯,需要保證sql語句的完整。所以需要首先使用?來佔位。 String sql = "select count(*) from user where username=? and password=?"; PreparedStatement ps = con.prepareStatement(sql); //將使用者填寫的值填充到編譯好的sql語句中 ps.setString(1, username); ps.setString(2, password); //執行sql語句 ResultSet rs = ps.executeQuery(); int count = 0; while(rs.next()){ count = rs.getInt(1); } if(count==1){ System.out.println("登入成功"); }else{ System.out.println("登入不成功"); } rs.close(); ps.close(); con.close(); }
PreparedStatement解決sql注入的原理
PreparedStatement 解決SQL注入原理,執行在SQL中引數以?佔位符的方式表示
select * from user where username = ? and password = ? ;
將帶有 ? 的SQL 傳送給資料庫完成編譯 (不能執行的SQL 帶有?的SQL 進行編譯 叫做預編譯),在SQL編譯後發現缺少兩個引數
PreparedStatement 可以將? 代替引數 傳送給資料庫伺服器,因為SQL已經編譯過,引數中特殊字元不會當做特殊字元編譯,無法達到SQL注入的目的
** PreparedStatement優點**
1、PreperedStatement可以避免SQL注入的問題。
2、Statement物件每次執行SQL語句時,都會對其進行編譯。當相同的SQL語句被執行被執行多次時,Statement物件就會使資料庫頻繁編譯相同的SQL語句,從而降低資料庫的效率。
PreparedStatement物件可對SQL語句進行預編譯。也就是說,當相同的SQL語句再次執行時,資料庫只需使用緩衝區中的資料,而不需要對SQL語句在次編譯,從而提高訪問效率。
3、並且PreperedStatement對於sql中的引數,允許使用佔位符的形式進行替換,簡化sql語句的編寫。可讀性變強。