JDBC模拟SQL注入和避免SQL注入

请添加图片描述

模拟用户登录
用户名:fdsa
密码:fdsa’ or ‘1’='1
select * from t_user where login_name=‘fdsa’ and login_pwd=‘fdsa’ or ‘1’='1’登录成功。以上随意输入一个用户名和密码,登录成功了,这种现象被称为SQL注入现象!

导致SOL注人的根本原因是什么?怎么解决?
导致SOL注入的根本原因是:用户不是一般的用户,用户是懂得程序的,输入的用户名信息以及密码信息中含有SOL语句的关健字,这个SQL语句的关健字和底层的SQL语句进行 “字符串拼接”,导致原SQL语句的含义被扭曲了。最最最最最最主要的原因是:用户提供的信息参与了SQL语句的编译。

主要因素是:这个程序是先进行的字符串拼接,然后再进行的SQL语句的编译,正好被注入。

模拟SQL注入代码实战


public class 模拟SQL注入 {
    
    
    public static void main(String[] args) {
    
    
        //初始化一个界面,可以让用户输入用户名和密码
        Map<String, String> map = initUI();

        //连接数据库验证用户名和密码是否正确
        boolean ok = checkNameAndPwd(map.get("a"),map.get("b"));
        System.out.println(ok ? "登陆成功" : "登录失败");
    }

    /**
     * 验证用户名和密码
     * @param a 登录名
     * @param b 登录密码
     * @return true表示登陆成功  false表示登录失败
     */
    private static boolean checkNameAndPwd(String a, String b) {
    
    
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        boolean ok = false; //默认登录失败的

        try {
    
    
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/feifei","root","297744");
            //3.获取数据库操作对象
            stmt = conn.createStatement();
            //4.执行SQL语句
            String sql = "select * from aa where name='"+ a +"' and mima = '"+b+"'";
            System.out.println(sql);
            rs = stmt.executeQuery(sql);//程序执行到此处,才会将sql语句发送到DBMS上,DBMS进行SQL语句编译
            //处理查询结果集
            //如果以上sql语句中用户和密码是正确的,那么结果集最多也就查询出一条记录,所以不需要while
            if (rs.next()){
    
    
                ok = true;
            }
        } catch (ClassNotFoundException | SQLException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            if (rs != null) {
    
    
                try {
    
    
                    rs.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (stmt != null) {
    
    
                try {
    
    
                    stmt.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
    
    
                try {
    
    
                    conn.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
        }
        return ok;
    }

    /**
     * 初始化界面,并接收用户的输入
     * @return 存储登录和登录密码的Map集合
     */
    private static Map<String,String> initUI() {
    
    
        System.out.println("欢迎使用系统,请输入用户名和密码进行身份确认");
        Scanner sc = new Scanner(System.in);
        System.out.println("用户名:");
        String  a = sc.next();
        System.out.println("密码:");
        String  b = sc.next();
        //将用户名和密码放到map集合中
        Map map = new HashMap();
        map.put("a",a);
        map.put("b",b);
        //返回Map
        return map;
    }


}

那么可以看到,通过SQL注入的方法就可以实现登录,那么我们应该怎么避免注入呢? SQL注入的根本原因是:先进行了字符串的拼接,然后再进行的编译

java.sql.statement接口的特点:先进行字符串的拼接,然后再进行sql语句的编译。
优点:使用statement可以进行sql语句的拼接。
缺点:因为拼接的存在,导致可能给不法分子机会。导致SQL注入。

java.sql.PreparedStatement接口的特点:先进行SQL语句的编译,然后再进行sql语句的传值。
优点:避免SQL注入。
缺点:没有办法进行sql语句的拼接,只能给sql语句传值。
PreparedStatement预编译的数据库操作对象。

代码实战使用PreparedStatement解决sql注入。

public class 解决SQL注入问题 {
    
    
    public static void main(String[] args) {
    
    
        //初始化一个界面,可以让用户输入用户名和密码
        Map<String, String> map = initUI();

        //连接数据库验证用户名和密码是否正确
        boolean ok = checkNameAndPwd(map.get("a"),map.get("b"));
        System.out.println(ok ? "登陆成功" : "登录失败");
    }

    /**
     * 验证用户名和密码
     * @param a 登录名
     * @param b 登录密码
     * @return true表示登陆成功  false表示登录失败
     */
    private static boolean checkNameAndPwd(String a, String b) {
    
    
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        boolean ok = false; //默认登录失败的

        try {
    
    
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/feifei","root","297744");

            //3.获取预编译的数据库操作对象
            //注意:一个问号?是一个占位符,一个占位符只能接受一个值/数据。占位符不能用单引号括起来
            String sql = "select * from aa where name= ? and mima = ?";
            stmt = conn.prepareStatement(sql);//此时发生sql给DBMS 进行sql语句的编译
            //给占位符?传值
            //jdbc中所有下标都是从1开始
            //怎么解决SQL注入的:即使用户信息中有sql关键字,但是不参加编译就没事。
            //stmt.setInt(1,444); 如果是setIng的话里面就要传入一个数字.setString是字符串
            stmt.setString(1,a);//1代表第一个?
            stmt.setString(2,b);//2代表第二个?

            //4.执行SQL语句
            //这个方法不能将SQL语句传进去,不能是这样rs = stmt.executeQuery(sql);
            rs = stmt.executeQuery();

            //5处理查询结果集
            //如果以上sql语句中用户和密码是正确的,那么结果集最多也就查询出一条记录,所以不需要while
            if (rs.next()){
    
    
                ok = true;
            }
        } catch (ClassNotFoundException | SQLException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            if (rs != null) {
    
    
                try {
    
    
                    rs.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (stmt != null) {
    
    
                try {
    
    
                    stmt.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
    
    
                try {
    
    
                    conn.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
        }
        return ok;
    }

    /**
     * 初始化界面,并接收用户的输入
     * @return 存储登录和登录密码的Map集合
     */
    private static Map<String,String> initUI() {
    
    
        System.out.println("欢迎使用系统,请输入用户名和密码进行身份确认");
        Scanner sc = new Scanner(System.in);
        System.out.println("用户名:");
        String  a = sc.next();
        System.out.println("密码:");
        String  b = sc.next();
        //将用户名和密码放到map集合中
        Map map = new HashMap();
        map.put("a",a);
        map.put("b",b);
        //返回Map
        return map;
    }
}

猜你喜欢

转载自blog.csdn.net/YOU__FEI/article/details/127155172
今日推荐