jdbc之防sql注入攻擊


1、SQL注入攻擊:
     由於dao中執行的SQL語句是拼接出來的,其中有一部分內容是由用戶從客戶端傳入,所以當用戶傳入的數據中包含sql關鍵字時,就有可能通過這些關鍵字改變sql語句的語義,從而執行一些特殊的操作,這樣的攻擊方式就叫做sql注入攻擊
  
    PreparedStatement利用預編譯的機制將sql語句的主干和參數分別傳輸給數據庫服務器,從而使數據庫分辨的出哪些是sql語句的主干哪些是參數,這樣一來即使參數中帶了sql的關鍵字,數據庫服務器也僅僅將他當作參數值使用,關鍵字不會起作用,從而從原理上防止了sql注入的問題

  PreparedStatement主要有如下的三個優點:
   1.可以防止sql注入
   2.由於使用了預編譯機制,執行的效率要高於Statement
   3.sql語句使用?形式替代參數,然后再用方法設置?的值,比起拼接字符串,代碼更加優雅.

  PreparedStatement 與Statment比較

                   1)語法不同:PreparedStatement可以使用預編譯的sql,而Statment只能使用靜態的sql

                   2)效率不同: PreparedStatement可以使用sql緩存區,效率比Statment高

                   3)安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。

 

/**
 * PreparedStatement執行sql語句
 * 
 *
 */
public class Demo1 {

    /**
     * 增加
     */
    @Test
    public void testInsert() {
        Connection conn = null;
        PreparedStatement stmt = null;
        try {
            //1.獲取連接
            conn = JdbcUtil.getConnection();
            
            //2.准備預編譯的sql
            String sql = "INSERT INTO student(NAME,gender) VALUES(?,?)"; //?表示一個參數的占位符
            
            //3.執行預編譯sql語句(檢查語法)
            stmt = conn.prepareStatement(sql);
            
            //4.設置參數值
            /**
             * 參數一: 參數位置  從1開始
             */
            stmt.setString(1, "李四");
            stmt.setString(2, "男");
            
            //5.發送參數,執行sql
            int count = stmt.executeUpdate();
            
            System.out.println("影響了"+count+"行");
            
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            JdbcUtil.close(conn, stmt);
        }
    }
    
    /**
     * 修改
     */
    @Test
    public void testUpdate() {
        Connection conn = null;
        PreparedStatement stmt = null;
        try {
            //1.獲取連接
            conn = JdbcUtil.getConnection();
            
            //2.准備預編譯的sql
            String sql = "UPDATE student SET NAME=? WHERE id=?"; //?表示一個參數的占位符
            
            //3.執行預編譯sql語句(檢查語法)
            stmt = conn.prepareStatement(sql);
            
            //4.設置參數值
            /**
             * 參數一: 參數位置  從1開始
             */
            stmt.setString(1, "王五");
            stmt.setInt(2, 9);
            
            //5.發送參數,執行sql
            int count = stmt.executeUpdate();
            
            System.out.println("影響了"+count+"行");
            
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            JdbcUtil.close(conn, stmt);
        }
    }
    
    /**
     * 刪除
     */
    @Test
    public void testDelete() {
        Connection conn = null;
        PreparedStatement stmt = null;
        try {
            //1.獲取連接
            conn = JdbcUtil.getConnection();
            
            //2.准備預編譯的sql
            String sql = "DELETE FROM student WHERE id=?"; //?表示一個參數的占位符
            
            //3.執行預編譯sql語句(檢查語法)
            stmt = conn.prepareStatement(sql);
            
            //4.設置參數值
            /**
             * 參數一: 參數位置  從1開始
             */
            stmt.setInt(1, 9);
            
            //5.發送參數,執行sql
            int count = stmt.executeUpdate();
            
            System.out.println("影響了"+count+"行");
            
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            JdbcUtil.close(conn, stmt);
        }
    }
    
    /**
     * 查詢
     */
    @Test
    public void testQuery() {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            //1.獲取連接
            conn = JdbcUtil.getConnection();
            
            //2.准備預編譯的sql
            String sql = "SELECT * FROM student"; 
            
            //3.預編譯
            stmt = conn.prepareStatement(sql);
            
            //4.執行sql
            rs = stmt.executeQuery();
            
            //5.遍歷rs
            while(rs.next()){
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String gender = rs.getString("gender");
                System.out.println(id+","+name+","+gender);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            //關閉資源
            JdbcUtil.close(conn,stmt,rs);
        }
    }
}

eg:模擬登陸

/**
 * 模擬用戶登錄效果
 * 
 *
 */
public class Demo2 {
    //模擬用戶輸入
    //private String name = "ericdfdfdfddfd' OR 1=1 -- ";
    private String name = "eric";
    //private String password = "123456dfdfddfdf";
    private String password = "123456";

    /**
     * Statment存在sql被注入的風險
     */
    @Test
    public void testByStatement(){
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //獲取連接
            conn = JdbcUtil.getConnection();
            
            //創建Statment
            stmt = conn.createStatement();
            
            //准備sql
            String sql = "SELECT * FROM users WHERE NAME='"+name+"' AND PASSWORD='"+password+"'";
            
            //執行sql
            rs = stmt.executeQuery(sql);
            
            if(rs.next()){
                //登錄成功
                System.out.println("登錄成功");
            }else{
                System.out.println("登錄失敗");
            }
            
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            JdbcUtil.close(conn, stmt ,rs);
        }
        
    }
    
    /**
     * PreparedStatement可以有效地防止sql被注入
     */
    @Test
    public void testByPreparedStatement(){
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            //獲取連接
            conn = JdbcUtil.getConnection();
            
            String sql = "SELECT * FROM users WHERE NAME=? AND PASSWORD=?";
            
            //預編譯
            stmt = conn.prepareStatement(sql);
            
            //設置參數
            stmt.setString(1, name);
            stmt.setString(2, password);
            
            //執行sql
            rs = stmt.executeQuery();
            
            if(rs.next()){
                //登錄成功
                System.out.println("登錄成功");
            }else{
                System.out.println("登錄失敗");
            }
            
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            JdbcUtil.close(conn, stmt ,rs);
        }
        
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM