複習_JDBC和sql注入問題

JDBC的全稱爲:java database connectivity (java和 數據庫的連接 )
在這裏插入圖片描述
JDBC六步

  1. 註冊驅動
  2. 建立數據庫的連接
  3. 通過con連接獲取到Statement實例
  4. statement執行sql語句,查詢到的結果集到ResultSet實例
  5. 從結果集中獲取數據
  6. 釋放資源
package JDBC;

import com.mysql.jdbc.Driver;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

public class JDBCTest {

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Connection con = null;
        Statement statement = null;
        try {
            //獲取連接
            con = getConnection();
            //創建statement
            statement = con.createStatement();
            // 執行添加語句
            String sql = "insert into user values('116','zhaoliu',28)";
            statement.executeUpdate(sql);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            //釋放資源
            release(con, statement, null);
        }
    }

    private static  String driverClass = "";
    private static String url = "";
    private static String username = "";
    private static String password = "";

    //解析properties文件只需要執行一次,所以放在靜態代碼塊中
    static{
        //首先創建Properties對象
        Properties properties = new Properties();
        //加載文件
        try {
            properties.load(new FileInputStream("src/jdbc.properties"));
            //獲取參數
            driverClass = properties.getProperty("driverClass");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            Class.forName(driverClass);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    public static Connection getConnection(){
        Connection con = null;
        try {
            //2.獲取連接
            con = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con;
    }

    //釋放資源
    public static void release(Connection con,Statement st,ResultSet rs){
        //6.釋放資源:先開後關,後開先關,最好放在finally代碼塊中
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if(con!=null){
            try {
                con.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}


driverClass=com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybd
username = root
password = root

2.sql注入問題

sql注入:由於沒有對用戶輸入進行充分檢查,而SQL又是拼接而成,在用戶輸入參數時,在參數中添加一些SQL 關鍵字,達到改變SQL運行結果的目的,也可以完成惡意攻擊。

案例:模擬登陸
執行如下sql語句:創建一個day06數據庫,創建一張user表,表中插入一條數據。

create table user(
id varchar(10) primary key,
username varchar(10),
password varchar(10)
);
insert into user values('1','admin','123456');
package JDBC;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Login {
    public static void main(String[] args) {
        String username = "admin' -- ";
        String password = "123";
        Connection con = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //首先獲取連接
            con = JDBCUtil.getConnection();

            //創建statement對象
            statement = con.createStatement();
            //發送sql語句,查詢數據庫是否存在這個用戶
            String sql = "select count(*) from user where username='" + username + "' and password = '" + password + "'";
            resultSet = statement.executeQuery(sql);

            int count = 0;
            while (resultSet.next()) {
                count = resultSet.getInt(1);
            }
            //如果不存在
            if (count == 0) {
                System.out.println("用戶登錄失敗");
            } else {
                //存在
                System.out.println("用戶登錄成功");
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            JDBCUtil.release(con, statement, resultSet);
        }
    }
}

執行代碼,可以發現用戶名爲 admin’ – ,密碼爲 1234 這樣的用戶是不存在的,但是盡然可以登錄成功。那麼這是什麼原因造成的呢?
將字符串拼接後的sql語句放在可視化工具中查看發現如下情況:
在這裏插入圖片描述
可以發現,後面密碼的驗證被註釋掉了。這樣豈不是誰都可以登錄了?

問題根本原因:
語句和用戶輸入的內容進行拼接,發送給數據庫編譯的時候,數據庫將用戶輸入的內容當成sql語句編譯了。
從而從根本上改變了我們開發者所期望sql語句原有的含義。導致程序受到sql攻擊。那麼原因知道了,我們怎麼解決的?

問題的解決方案:
我們需要首先將sql語句所代表的含義確定下來,然後再向編譯好的sql語句中填充用戶輸入的內容。這樣用戶輸入的內容就不會再被編譯了。所以需要我們學習preparedStatement向數據庫發送預編譯的sql語句。

2.1 PreparedStatement解決sql注入 重要步驟:

PreparedStatement是Statement的子接口,它的實例對象可以通過調用Connection.preparedStatement(sql)方法獲得
注意:sql提前創建好的。sql語句中需要參數。使用?進行佔位。

  1. conn.prepareStatement(sql);
    需要你事先傳遞sql。如果sql需要參數,使用?進行佔位。
  2. 設置參數(執行sql之前):prepStmt.setXXX(int index, 要放入的值)
    根據不同類型的數據進行方法的選擇。第一個參數表示的是?出現的位置。從1開始計數,有幾個問號,就需要傳遞接個參數。方法的參數說明:
    第一個參數:int index ;表示的是問號出現的位置。 問號是從1開始計數
    第二個參數:要問號的位置傳入的值。
  3. 執行,不需要在傳遞sql了。
    prepStmt.executeQuery();—執行select
    prepStmt.executeUpdate();—執行insert,delete,update
package JDBC;

import java.sql.*;

public class Login {
    public static void main(String[] args) {
        String username = "admin";
        String password = "123456";
        Connection con = null;
        PreparedStatement prepareStatement = null;
        ResultSet resultSet = null;
        try {
            //首先獲取連接
            con = JDBCUtil.getConnection();

            String sql = "select COUNT(*) from user where username=? and password = ?";
            //創建preparedStatement對象,對sql進行編譯
            prepareStatement = con.prepareStatement(sql);
            // 設置參數
            prepareStatement.setString(1, username);
            prepareStatement.setString(2, password);
            resultSet = prepareStatement.executeQuery();
            int count = 0;
            while (resultSet.next()) {
                count = resultSet.getInt(1);
            }
            //如果不存在
            if (count == 0) {
                System.out.println("用戶登錄失敗");
            } else {
                //存在
                System.out.println("用戶登錄成功");
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            JDBCUtil.release(con, prepareStatement, resultSet);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章