1. 程式人生 > 其它 >Mysql 的sql注入是什麼?怎麼解決?

Mysql 的sql注入是什麼?怎麼解決?

技術標籤:mysqlmysql

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優點**

相對於Statement物件而言:
1、PreperedStatement可以避免SQL注入的問題。
2、Statement物件每次執行SQL語句時,都會對其進行編譯。當相同的SQL語句被執行被執行多次時,Statement物件就會使資料庫頻繁編譯相同的SQL語句,從而降低資料庫的效率。
PreparedStatement物件可對SQL語句進行預編譯。也就是說,當相同的SQL語句再次執行時,資料庫只需使用緩衝區中的資料,而不需要對SQL語句在次編譯,從而提高訪問效率。
3、並且PreperedStatement對於sql中的引數,允許使用佔位符的形式進行替換,簡化sql語句的編寫。可讀性變強。