JDBC中Statement的Sql注入问题详解

 更新时间:2023年10月16日 11:30:32   作者:发光吖  
这篇文章主要介绍了JDBC中Statement的Sql注入问题详解,sql注入攻击指的是通过构建特殊的输入作为参数传入web应用程序,而这些输入大都是sql语法里的一些组合,通过执行sql语句进而执行攻击者所要做的操作,需要的朋友可以参考下

Statement的Sql注入问题

sql注入攻击指的是通过构建特殊的输入作为参数传入web应用程序,而这些输入大都是sql语法里的一些组合,通过执行sql语句进而执行攻击者所要做的操作,其产生的主要原因在于应用程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。

我们通过一个用户登录的小案例来大致了解sql注入的情况:(Oracle数据库环境)

首先准备一张表t_user:

在这里插入图片描述

create table t_user(
	name varchar2(10) primary key,
	password varchar2(10) not null
)

插入一些测试数据:

insert into t_user(name,password) values('tom','123');
insert into t_user(name,password) values('mary','456');
commit;

所使用的数据库驱动:ojdbc8.jar

用JDBC连接数据库,写一个登录案例:

public class TestSqlInjection {
	public static void main(String[] args) {
		String driverClass = "oracle.jdbc.OracleDriver";
		String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
		String user = "briup";
		String password = "briup";

		@SuppressWarnings("resource")
		Scanner input = new Scanner(System.in);
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			Class.forName(driverClass);
			conn = DriverManager.getConnection(url, user, password);
			stmt = conn.createStatement();
			System.out.println("请输入用户名:");
			String uname = input.nextLine();
			System.out.println("请输入密码:");
			String upass = input.nextLine();
			String sql = "SELECT name,password FROM t_user WHERE name='" + uname + "' AND password='" + upass + "'";
			// uname xxx
			// upass xxx' or '1'='1
			rs = stmt.executeQuery(sql);
			if (rs.next()) {
				System.out.println("登录成功");
				// 这时候我们认为用户名和密码都正确情况下查询出来的用户肯定只有一条
				System.out.println("欢迎您," + uname);
			} else {
				System.err.println("用户名或密码错误!");
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

效果:

在这里插入图片描述

很显然使用Statement的确产生了sql注入的问题。

但是使用PreparedStatement可以有效解决这个问题。

public class TestSqlInjection {
	public static void main(String[] args) {
		String driverClass = "oracle.jdbc.OracleDriver";
		String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
		String user = "briup";
		String password = "briup";

		@SuppressWarnings("resource")
		Scanner input = new Scanner(System.in);
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			Class.forName(driverClass);
			conn = DriverManager.getConnection(url, user, password);
			String sql = "SELECT name,password FROM t_user WHERE name=? AND password=?";
			ps = conn.prepareStatement(sql);
	        //uname xxx
	        //upass xxx' or '1'='1
			System.out.println("请输入用户名:");
			String uname = input.nextLine();
			ps.setString(1, uname);
			System.out.println("请输入密码:");
			String upass = input.nextLine();
			ps.setString(2, upass);
			rs = ps.executeQuery();
			if (rs.next()) {
				System.out.println("登录成功");
				System.out.println("欢迎您," + uname);
			} else {
				System.err.println("用户名或密码错误!");
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

PreparedStatement 除了可以防止sql注入,在执行大量重复性插入语句时,也会明显提升程序运行的性能,同时避免了繁琐的字符串拼接操作。

对比:

Statement ,是每次执行一个sql语句,就要把一个完成的sql语句发送给数据库进行执行,然后取回返回的结果。

PreparedStatement ,可以把一个sql语句的结构,提前发送给数据库进行预处理,然后在专门给发送要操作的具体的值,在数据量大的时候,这种方式会大大提高执行效率。

到此这篇关于JDBC中Statement的Sql注入问题详解的文章就介绍到这了,更多相关Statement的Sql注入问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中的@Async异步功能详解

    Java中的@Async异步功能详解

    这篇文章主要介绍了Java中的@Async异步功能详解,@Async注解,可以实现异步处理的功能,它可以有返回值,或者直接在新线程时并行执行一个任务,对于异步来说,它的执行是有条件的,你需要把异步代码块放在单独的类里,需要的朋友可以参考下
    2023-11-11
  • 详解Java中native关键字

    详解Java中native关键字

    这篇文章主要为大家详细介绍了Java中native关键字,什么是Native Method
    2016-02-02
  • java实现简单TCP聊天程序

    java实现简单TCP聊天程序

    这篇文章主要为大家详细介绍了java实现简单TCP聊天程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • Java实现Twitter的分布式自增ID算法snowflake

    Java实现Twitter的分布式自增ID算法snowflake

    这篇文章主要介绍了Java实现Twitter的分布式自增ID算法snowflake,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • SpringBoot2 task scheduler 定时任务调度器四种方式

    SpringBoot2 task scheduler 定时任务调度器四种方式

    这篇文章主要介绍了SpringBoot2 task scheduler 定时任务调度器四种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • Java 实战项目锤炼之校园宿舍管理系统的实现流程

    Java 实战项目锤炼之校园宿舍管理系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+jsp+javaweb+mysql+ajax实现一个校园宿舍管理系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • Java设计模式之桥接模式的示例详解

    Java设计模式之桥接模式的示例详解

    桥梁模式是对象的结构模式。又称为柄体(Handle and Body)模式或接口(Interface)模式。本文将通过示例来详细讲解一下这个模式,感兴趣的可以学习一下
    2022-02-02
  • BlockingQueue队列处理高并发下的日志

    BlockingQueue队列处理高并发下的日志

    这篇文章主要介绍了BlockingQueue队列处理高并发下的日志示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • 带你盘点Java的五种运算符

    带你盘点Java的五种运算符

    这篇文章主要介绍了Java基本数据类型和运算符,结合实例形式详细分析了java基本数据类型、数据类型转换、算术运算符、逻辑运算符等相关原理与操作技巧,需要的朋友可以参考下
    2021-07-07
  • java.lang.OutOfMemoryError: Metaspace异常解决的方法

    java.lang.OutOfMemoryError: Metaspace异常解决的方法

    这篇文章主要介绍了java.lang.OutOfMemoryError: Metaspace异常解决的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03

最新评论