JDBC中存在的SQL注入问题及Statement对象和PreparedStatement对象的区别

JDBC中存在的SQL注入问题及Statement对象和PreparedStatement对象的区别

JDBC中存在的SQL注入问题

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/*
实现功能:
    1、需求:模拟用户登录功能的实现。
    2、业务描述:
        程序运行的时候,提供一个输入的入口,然用户输入用户名和密码
        用户输入用户名和密码之后,提交信息,java程序收集用户信息
        java线程连接数据库验证用户名和密码是否合法
        合法:显示登录成功
        不合法:显示登录失败

        参见user_login.sql脚本
    3、sql注入(安全隐患)
        请输入用户名:fdsa
        请输入密码:fdsa'or'1'='1
        登录成功

    4、导致SQL注入的根本原因是什么?
        用户输入的信息中有SQL语句的关键字,并且这些关键字参与SQL语句的编译过程
        导致SQL语句原意被扭曲,进而达到SQL注入。

 */
public class JDBCTest06 {
    
    
    public static void main(String[] args) {
    
    
        // 1.初始化界面
        Map<String,String> userLoginInfo = initUI();
        // 2.验证用户名密码
        boolean loginSuccess = login(userLoginInfo);
        // 3.输出结果
        System.out.println(loginSuccess ? "登录成功" : "登录失败");


        //System.out.println(in_user + "," + in_password);
    }

    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return false 登录失败 true 登录成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
    
    
        // 打标记
        boolean loginSuccess = false;

        // 获取输入的用户名密码
        String loginName = userLoginInfo.get("loginName");
        String loginPwd = userLoginInfo.get("loginPwd");

        // JDBC代码
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        // 注册驱动
        try {
    
    
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }


        try {
    
    
            // 获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root", "123");

            // 获取数据库操作对象
            statement = connection.createStatement();

            // 执行sql语句
            resultSet = statement.executeQuery("select * from t_user where loginName='" + loginName + "' and loginPwd='"+ loginPwd +"'");

            // 处理查询结果集
            if (resultSet.next()){
    
    
                loginSuccess = true;
            }

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally {
    
    
            // 释放资源
            if (resultSet != null){
    
    
                try {
    
    
                    resultSet.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (statement != null) {
    
    
                try {
    
    
                    statement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (connection != null){
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面
     * @return 用户输入的用户名和密码等登录信息
     */
    private static Map<String,String> initUI() {
    
    

        Scanner scanner = new Scanner(System.in);

        System.out.print("请输入用户名:");
        String loginName = scanner.next();

        System.out.print("请输入密码:");
        String loginPwd = scanner.next();

        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);

        return userLoginInfo;
    }
}

JDBC中解决SQL注入

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/*
1、解决SQL注入问题
    只要用户提供的信息不参与SQL语句的编译过程问题就解决了
    即使用户提供的信息中含有SQL语句的关键字,但是不参与编译
    就不起作用,那么就必须使用java.sql.PreparedStatement
    PreparedStatement接口继承了java.sql.Statement
    PreparedStatement是属于预编译的操作对象
    PreparedStatement原理是先对SQL语句框架进行编译,然后再给SQL语句传“值”

2、解决SQL注入的关键是什么?
    用户提供的信息中即使含有SQL语句的关键字,但是这些关键字不参与编译,不起作用。

3、比较Statement和PreparedStatement
    -Statement存在SQL注入问题,PreparedStatement解决了SQL注入问题
    -Statement编译一次执行一次,PreparedStatement编译一次可执行n次,PreparedStatement效率更高
    —PreparedStatement会在编译阶段做类型的安全检查
    综上所述,PreparedStatement使用较多,Statement使用极少

4、什么情况下必须使用Statement呢?
    业务方面要求必须支持SQL注入时
    Statement支持SQL注入,业务方面要求进行SQL拼接的,必须使用Statement
 */
public class JDBCTest07 {
    
    
    public static void main(String[] args) {
    
    
        // 1.初始化界面
        Map<String,String> userLoginInfo = initUI();
        // 2.验证用户名密码
        boolean loginSuccess = login(userLoginInfo);
        // 3.输出结果
        System.out.println(loginSuccess ? "登录成功" : "登录失败");


        //System.out.println(in_user + "," + in_password);
    }

    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return false 登录失败 true 登录成功
     */
    private static boolean login(Map<String, String> userLoginInfo) {
    
    
        // 打标记
        boolean loginSuccess = false;

        // 获取输入的用户名密码
        String loginName = userLoginInfo.get("loginName");
        String loginPwd = userLoginInfo.get("loginPwd");

        // JDBC代码
        Connection connection = null;
        PreparedStatement preparedStatement = null; // 使用预编译的数据库操作对象
        ResultSet resultSet = null;

        // 1、注册驱动
        try {
    
    
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }


        try {
    
    
            // 2、获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root", "123");

            // 3、获取预编译的数据库操作对象
            // 一个?代表一个占位符,将来一个?接收一个“值”,占位符不能使用单引号括起来
            String sql = "select * from t_user where loginName=? and loginPwd=?";
            // 程序执行到这里,会发送SQL语句框子给DBMS,然后DBMS进行SQL语句的预编译。
            preparedStatement = connection.prepareStatement(sql);

            // 给占位符?传值(第一个问号下标是1,第二个问号下标是2,JDBC中所有下标从1开始)
            preparedStatement.setString(1,loginName);
            preparedStatement.setString(2,loginPwd);

            // 4、执行sql语句
            resultSet = preparedStatement.executeQuery();

            // 5、处理查询结果集
            if (resultSet.next()){
    
    
                loginSuccess = true;
            }

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally {
    
    
            // 6、释放资源
            if (resultSet != null){
    
    
                try {
    
    
                    resultSet.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (preparedStatement != null) {
    
    
                try {
    
    
                    preparedStatement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (connection != null){
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面
     * @return 用户输入的用户名和密码等登录信息
     */
    private static Map<String,String> initUI() {
    
    

        Scanner scanner = new Scanner(System.in);

        System.out.print("请输入用户名:");
        String loginName = scanner.next();

        System.out.print("请输入密码:");
        String loginPwd = scanner.next();

        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",loginName);
        userLoginInfo.put("loginPwd",loginPwd);

        return userLoginInfo;
    }
}

必须使用Statement对象的情况

import java.sql.*;
import java.util.ArrayList;
import java.util.Scanner;

/*
用户在控制台输入desc就是降序,输入asc就是升序
 */
public class JDBCTest08 {
    
    
    public static void main(String[] args) {
    
    
        // 初始化用户界面,接收用户输入
        String info = initUI();

        // 执行SQL
        ArrayList<String> arrayLists = excuteDQL(info);

        // 显示查询结果
        show(arrayLists);
    }

    private static void show(ArrayList<String> arrayLists) {
    
    
        for (String list : arrayLists) {
    
    
            System.out.println(list);
        }
    }

    private static ArrayList<String> excuteDQL(String info) {
    
    
        ArrayList<String> resultLists = new ArrayList<>();

        //JDBC编程
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        // 注册驱动
        try {
    
    
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }

        try {
    
    
            // 获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","123");

            // 获取数据库操作对象
            statement = connection.createStatement();

            // 执行SQL语句
            String sql = "select empno,ename,sal from emp order by sal " + info;
            resultSet = statement.executeQuery(sql);

            // 处理查询结果集
            while (resultSet.next()) {
    
    
                String empno = resultSet.getString("empno");
                String ename = resultSet.getString("ename");
                String sal = resultSet.getString("sal");
                resultLists.add(empno + "," + ename + "," + sal);
            }

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally {
    
    
            //释放资源
            if (resultSet != null){
    
    
                try {
    
    
                    resultSet.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (statement != null){
    
    
                try {
    
    
                    statement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if(connection != null){
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
        }


        return resultLists;
    }

    private static String initUI() {
    
    

        Scanner scanner = new Scanner(System.in);

        System.out.println("升序输入ASC,降序输入DESC");
        String info = scanner.next();

        return info;
    }


}

使用PreparedStatement完成DML操作

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/*
PreparedStatement完成DML操作(insert delete update)
 */
public class JDBCTest09 {
    
    
    public static void main(String[] args) {
    
    

        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
    
    
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");

        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }

        try {
    
    
            /*
            //PreparedStatement完成insert操作
            //2.获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","123");

            //3.获取预编译的数据库操作对象
            String sql = "insert into dept(deptno,dname,loc) values(?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,50);
            preparedStatement.setString(2,"销售部");
            preparedStatement.setString(3,"shanghai");

            //4.执行SQL语句
            int count = preparedStatement.executeUpdate();
            System.out.println(count == 1 ? "执行成功" : "执行失败");
            */

            /*
            //PreparedStatement完成update操作
            //2.获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","123");

            //3.获取预编译的数据库操作对象
            String sql = "update dept set dname=?,loc=? where deptno=?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"宣传部");
            preparedStatement.setString(2,"北京");
            preparedStatement.setInt(3,50);

            //4.执行SQL语句
            int count = preparedStatement.executeUpdate();
            System.out.println(count == 1 ? "执行成功" : "执行失败");
            */

            //PreparedStatement完成delete操作
            //2.获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","123");

            //3.获取预编译的数据库操作对象
            String sql = "delete from dept where deptno=?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,50);

            //4.执行SQL语句
            int count = preparedStatement.executeUpdate();
            System.out.println(count == 1 ? "执行成功" : "执行失败");

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        } finally {
    
    
            //6.释放资源
            if (preparedStatement != null) {
    
    
                try {
    
    
                    preparedStatement.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
            if (connection != null) {
    
    
                try {
    
    
                    connection.close();
                } catch (SQLException throwables) {
    
    
                    throwables.printStackTrace();
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45017232/article/details/112999686