1. 程式人生 > 其它 >Java JDBC 控制檯使用者登入測試 及 登入存在SQL注入的解決

Java JDBC 控制檯使用者登入測試 及 登入存在SQL注入的解決

實現功能:

1.使用者登入

2.java連線資料庫驗證,控制檯顯示成功或失敗

idea 新建java空專案,新建測試類LoginTest

public static void main(String[] args) {

    //初始化一個介面
    Map<String,String> userLoginInfo = initUI();

    //驗證使用者名稱和密碼
    boolean loginSuccess = login(userLoginInfo);

    //最後輸出結果
    System.out.println(loginSuccess?"登陸成功":"登入失敗");
}
private static boolean login(Map<String, String> userLoginInfo) {
 //打標記
    boolean loginSuccess = false;
  //單獨定義變數
    String loginName =userLoginInfo.get("loginName");
    String loginPwd = userLoginInfo.get("loginPwd");

   //JDBC程式碼
    Connection conn =null;
    Statement stmt=null;
    ResultSet re =null;


    try {
        //1.註冊驅動
        Class.forName("com.mysql.jdbc.Driver");
        //2.獲取連結
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user","root","root");
        //3.獲取資料庫操作物件
        stmt = conn.createStatement();
        //4.執行SQL
        String sql = "select * from t_user where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"' ";
        //以上正好完成了SQL語句的拼接,以下程式碼的含義是傳送SQL語句給DBMS,DBMS進行SQL編譯
        re = stmt.executeQuery(sql);//執行查詢,將SQL傳過來
        //5.處理結果集
        if(re.next()){
            //登陸成功
            loginSuccess = true;

        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        //6.資源釋放
        if(re!=null) {
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(stmt !=null) {
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null) {
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    return loginSuccess;
}
private static Map<String, String> initUI() {
    Scanner s = new Scanner(System.in);

    //讀取使用者名稱
    System.out.print("使用者名稱:");
    String loginName = s.nextLine();

    //讀取密碼
    System.out.println("密碼:");
    String loginPwd =s.nextLine();

    //將資料組裝到Map中
    Map<String,String> userLoginInfo = new HashMap<>();
    userLoginInfo.put("loginName",loginName);
    userLoginInfo.put("loginPwd",loginPwd);

    //返回Map
    return userLoginInfo;
}

執行結果:

登陸成功

存在問題 : SQL注入

使用者名稱:qwer

密碼:qwer' or '1'='1

此時能夠能錄成功,這種現象被稱為SQL注入

導致SQL注入的根本原因:

使用者輸入的資訊中含有SQL語句的關鍵字,並且這些關鍵字參與SQL的編譯過程,導致SQL語句的原意被扭曲,進而達到SQL注入

其中

String sql = "select * from t_user where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"' ";

re = stmt.executeQuery(sql);//執行查詢,將SQL傳過來

上行程式碼正好完成了SQL語句的拼接,下行程式碼的含義是傳送SQL語句給DBMS,DBMS進行SQL編譯,正好將使用者提供的“非法資訊”編譯進去,扭曲了原有SQL語句

解決方法:

只要使用者提供的資訊不參與編譯過程,問題就解決了,使用PrepareStatement替換Statement

新建類LoginTest02

public static void main(String[] args) {

    //初始化一個介面
    Map<String,String> userLoginInfo = initUI();

    //驗證使用者名稱和密碼
    boolean loginSuccess = login(userLoginInfo);

    //最後輸出結果
    System.out.println(loginSuccess?"登陸成功":"登入失敗");
}
private static boolean login(Map<String, String> userLoginInfo) {

    boolean loginSuccess = false;
    //單獨定義變數
    String loginName =userLoginInfo.get("loginName");
    String loginPwd = userLoginInfo.get("loginPwd");

    //JDBC程式碼
    Connection conn =null;
    //這裡使用prepareStatement(預編譯的資料庫操作物件)
    PreparedStatement ps=null;
    ResultSet re =null;


    try {
        //1.註冊驅動
        Class.forName("com.mysql.jdbc.Driver");
        //2.獲取連結
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user","root","root");
        //3.獲取預編譯的資料庫操作物件
        String sql = "select * from t_user where loginName = ? and loginPwd = ? ";
        //SQL語句的框子。問號是佔位符,不加引號。一號問號接受一個值
        // 程式執行到此處,會發送SQL語句框子給DBMS,然後DBMS進行SQL語句的預先編譯
        //給佔位符?傳值 (第一個問號下標是1,第二個問號下標是2,JDBC所有下標 從1開始)
        //4.執行SQL 
        ps = conn.prepareStatement(sql);
     
        ps.setString(1,loginName);
        ps.setString(2,loginPwd);
             
        re = ps.executeQuery();
        //5.處理結果集
        if(re.next()){
            //登陸成功
            loginSuccess = true;

        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        //6.資源釋放
        if(re!=null) {
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(ps !=null) {
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null) {
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    return loginSuccess;
}
private static Map<String, String> initUI() {
    Scanner s = new Scanner(System.in);

    //讀取使用者名稱
    System.out.print("使用者名稱:");
    String loginName = s.nextLine();

    //讀取密碼
    System.out.print("密碼:");
    String loginPwd =s.nextLine();

    //將資料組裝到Map中
    Map<String,String> userLoginInfo = new HashMap<>();
    userLoginInfo.put("loginName",loginName);
    userLoginInfo.put("loginPwd",loginPwd);

    //返回Map
    return userLoginInfo;
}

執行結果:

SQL注入問題解決,登入正常

解決SQL注入問題的關鍵:

使用者提供的資訊中心即使含有SQL語句的關鍵字,但這些關鍵字沒有參與編譯,只要使用者提供的資訊不參與編譯過程,問題就解決了
要想使用者資訊不參與SQL語句的編譯,那麼必須使用java.sql.PreparedStatement
PreparedStatement介面繼承了java.sql.Statement,是屬於預編譯的資料庫操作物件
原理是預先對SQL語句框架進行編譯,然後再給SQL傳值

本文來自部落格園,作者:大星星不見了,轉載請註明原文連結:https://www.cnblogs.com/dxxbjl/p/15084523.html