【数据库编程】4.Statement与PreparedStatement

1. Statement

1.1 基本介绍

  1. Statement用于执行静态SQL语句并返回其生成的结果的对象。
  2. Statement对象执行SQL语句存在SQL注入风险。
  3. SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库。
  4. 防范SQL注入,只要用PreparedStatement(Statement子接口)替代Statement即可。

1.2 SQL注入案例

创建一个admin表用于演示SQL注入,并插入一条数据。代码如下:

-- 创建一个用户表
CREATE TABLE admin (
	`name` VARCHAR(32) NOT NULL UNIQUE,
	`pwd` VARCHAR(32) NOT NULL DEFAULT ''
) CHARACTER SET = utf8;

-- 添加一条数据
INSERT INTO admin VALUES ('alan', '123');

编写一个Java程序,在控制台中输入用户名和密码模拟登陆,使用Statement执行拼接的SQL语句。如果用户名和密码正确就显示“登陆成功”,否则显示“登陆失败”。代码如下:

public static void testSQLInjection() throws Exception {
    // 控制台输入用户名和密码
    Scanner scanner = new Scanner(System.in);
    System.out.print("请输入用户名:");
    String name = scanner.nextLine();
    System.out.print("请输入密码:");
    String pwd = scanner.nextLine();
    // 获取值
    Properties properties = new Properties();
    properties.load(new FileInputStream("src\\mysql.properties"));
    String user = properties.getProperty("user");
    String password = properties.getProperty("password");
    String dirver = properties.getProperty("dirver");
    String url = properties.getProperty("url");
    // 注册驱动
    Class.forName(dirver);
    // 得到连接和Statement
    Connection connection = DriverManager.getConnection(url, user, password);
    Statement statement = connection.createStatement();
    // 组织SQL
    String sql = "select count(name) from admin where name = '" + name + "' and pwd = '" + pwd + "'";
    // 执行SQL获得结果集
    ResultSet resultSet = statement.executeQuery(sql);
    // 是否登陆成功
    System.out.println(resultSet.next() ? "登陆成功" : "登陆失败");
    // 关闭连接
    resultSet.close();
    statement.close();
    connection.close();
}

当用户名输入【1' or】、密码输入【or '1'= '1】后,显示登陆成功。

image-20210811103111620

此时的SQL语句拼接结果是

SELECT NAME FROM admin WHERE NAME = '1' OR' and pwd = 'OR '1'= '1'

2. PreparedStatement

2.1 基本介绍

  1. PreparedStatement执行的SQL语句中的参数用问号(?)来标识,调用PreparedStatement对象的setXxx()方法来设置这些参数。setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个参数是设置SQL语句中的参数的值。
  2. 调用executeQuery(),执行查询,返回ResultSet对象。
  3. 调用executeUpdate(),执行更新,包括增、删、改。

2.2 预处理的优点

  1. 不再使用加号(+)拼接SQL语句,减少语法错误。
  2. 有效解决了SQL注入问题。
  3. 大大减少了编译次数,效率较高。

2.3 防范SQL注入案例

public static void testNoSQLInjection() throws Exception {
    // 控制台输入用户名和密码
    Scanner scanner = new Scanner(System.in);
    System.out.print("请输入用户名:");
    String name = scanner.nextLine();
    System.out.print("请输入密码:");
    String pwd = scanner.nextLine();
    // 获取值
    Properties properties = new Properties();
    properties.load(new FileInputStream("src\\mysql.properties"));
    String user = properties.getProperty("user");
    String password = properties.getProperty("password");
    String dirver = properties.getProperty("dirver");
    String url = properties.getProperty("url");
    // 注册驱动
    Class.forName(dirver);
    // 得到连接和Statement
    Connection connection = DriverManager.getConnection(url, user, password);
    // 编写SQL
    String sql = "select name from admin where name=? and pwd=?";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    // 给占位符赋值
    preparedStatement.setString(1, name);
    preparedStatement.setString(2, pwd);
    // 执行SQL获得结果集
    ResultSet resultSet = preparedStatement.executeQuery();
    // 是否登陆成功
    System.out.println(resultSet.next() ? "登陆成功" : "登陆失败");
    // 关闭连接
    resultSet.close();
    preparedStatement.close();
    connection.close();
}

使用PreparedStatement后,用户名输入【1' or】、密码输入【or '1'= '1】后,显示“登陆失败”,解决了SQL注入。

image-20210811103029618

posted @   爵岚  阅读(109)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示