JDBC(有趣的sql语句带来的漏洞以及解决办法)

数据库查找(漏洞 bug)小案例:

  public class Test01 {
        public static void main(String[] args) {
            Connection conn=null;
            //建立连接
            try {
                conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123456");
                //创建Statement
                Statement stmt=conn.createStatement();
                String name="name' or";
                String pwd=" != '";
                //声明sql
                String sql="SELECT * FROM USER WHERE UNAME = '"+name+"' AND PWD = '"+pwd+"'";
                System.out.println(sql);
                //结果集
                ResultSet rs=stmt.executeQuery(sql);
                boolean flag=false;
                while(rs.next()){
                    flag=true;
                }
                System.out.println(flag);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            
        }
    }

打印结果为:

   SELECT * FROM USER WHERE UNAME = 'name' or' AND PWD = ' != ''
    true

分析结果:
    以上程序模拟的是用户进行登陆,程序查找数据库返回结果。
    通过拼装sql语句,可以查询到true,这明显是一个bug。那么如何进行解决呢?

对上一个案例问题进行解决+新的知识点(PreparedStatement以及事务的提交)实例:

    public class Test02 {
        public static void main(String[] args) {
            test();
        
            test2();
        }
        
        public static void test2(){
            Connection conn=null;
            PreparedStatement pstmt=null;//使用PreparedStatement可以防止sql注入
            try {
                //创建连接 rewriteBatchedStatements=true:设置批处理
                conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test?"
                        + "rewriteBatchedStatements=true","root","123456");
                
                User u=new User("zhangsan","123");
                
                //改变提交的方式,改为手动提交
                conn.setAutoCommit(false);
                //sql语句
                String sql="INSERT INTO USER (UNAME,PWD) VALUES (?,?)";
                //创建Statement
                pstmt=conn.prepareStatement(sql);
                
                long start=System.currentTimeMillis();
                for(int i=0;i<100;i++){
                    //设置值
                    pstmt.setString(1, u.getName());
                    pstmt.setString(2, u.getPwd());
                    //添加到批处理中
                    pstmt.addBatch();
                }
                //执行批处理
                pstmt.executeBatch();
                //手动提交事务
                conn.commit();
                long end=System.currentTimeMillis();
                System.out.println("使用PreparedStatement使用时间:"+(end-start));
            } catch (SQLException e) {
                e.printStackTrace();
                //如果发生异常,则需要进行回滚
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }finally{
                try {
                    if (pstmt != null) {
                        pstmt.close();
                    } 
                    if(conn!=null){
                        conn.close();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
        public static void test(){
            Connection conn=null;
            Statement stmt=null;//使用PreparedStatementf
            try {
                //创建连接
                conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123456");
                stmt=conn.createStatement();
                long start=System.currentTimeMillis();
                for(int i=0;i<100;i++){
                    User u=new User("zhangsan","123");
                    //sql语句
                    String sql="INSERT INTO USER (UNAME,PWD) VALUES ('"+u.getName()+i+"','"+u.getPwd()+"')";
                    //创建Statement
                    stmt.executeUpdate(sql);
                }
                long end=System.currentTimeMillis();
                System.out.println("使用Statement使用时间:"+(end-start));
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                try {
                    if (stmt != null) {
                        stmt.close();
                    } 
                    if(conn!=null){
                        conn.close();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
            
        }
    
    }
    class User{
        private int id;
        private String name;
        private String pwd;
        public User(int id, String name, String pwd) {
            super();
            this.id = id;
            this.name = name;
            this.pwd = pwd;
        }
        
        public User(String name, String pwd) {
            super();
            this.name = name;
            this.pwd = pwd;
        }
    
        public User() {
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getPwd() {
            return pwd;
        }
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
        @Override
        public String toString() {
            return "User [id=" + id + ", name=" + name + ", pwd=" + pwd + "]";
        }
        
    }

打印结果为:

 使用Statement使用时间:5758
 使用PreparedStatement使用时间:116    

程序分析:
    1、PreparedStatement :可以解决第一个sql注入的问题,PreparedStatement采用占位符,数据库内部进行sql的拼接。
    2、PreparedStatement可以进行处理操作。
    3、jabc默认是自动提交事务conncetion.autoCommite(true);,我们可以设置不进行自动提交事务,等所有操作处理完成之后              一起进行提交。  
    4、手动提交: conncetion.autoCommite(false);
    5、提交:connection.commite() 回滚:connection.rollback();    
    6、对于批处理,PreparedStatement的处理效率比Statement的效率要高。

猜你喜欢

转载自blog.csdn.net/ToBe_Coder/article/details/81749362
今日推荐