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注入问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IntelliJ IDEA配置Maven阿里云镜像加速源的全流程

    IntelliJ IDEA配置Maven阿里云镜像加速源的全流程

    国内网络访问 Maven 中央仓库经常超时、依赖下载极慢或失败,配置阿里云等国内镜像后,Java 项目依赖下载飞快,极大提升开发效率,是中国开发者必做优化,本文就给大家介绍了IntelliJ IDEA配置Maven阿里云镜像加速源的全流程,需要的朋友可以参考下
    2025-09-09
  • MybatisPlus中的删除和逻辑删除及区别介绍

    MybatisPlus中的删除和逻辑删除及区别介绍

    这篇文章主要介绍了MybatisPlus中的删除和逻辑删除的相关知识,删除又分为逻辑删除和物理删除,那么它们有什么区别呢?在本文给大家详细介绍,感兴趣的朋友跟随小编一起看看吧
    2020-08-08
  • 详解SpringBoot集成Hera日志管理新方案

    详解SpringBoot集成Hera日志管理新方案

    本文介绍了SpringBoot集成Hera日志平台的完整方案,SpringBoot与Hera的集成步骤包括环境准备、核心参数配置、无侵入式日志输出和控制台高效排查,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • SpringBoot请求处理之常用参数注解介绍与源码分析

    SpringBoot请求处理之常用参数注解介绍与源码分析

    SpringBoot是一种整合Spring技术栈的方式(或者说是框架),同时也是简化Spring的一种快速开发的脚手架,本篇让我们一起学习请求处理、常用注解和方法参数的小技巧
    2022-10-10
  • Java 枚举的定义、使用详解

    Java 枚举的定义、使用详解

    本文介绍了Java中的枚举(enum)概念,包括枚举的定义、使用和常用方法,枚举是一种特殊的类,用于定义一组常量,使得代码更具有可读性和可维护性,枚举类默认继承自java.lang.Enum类,且不能被继承,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • 使用lombok@Data存在extends时需要注意的问题

    使用lombok@Data存在extends时需要注意的问题

    在Java编程中,正确实现equals方法是保证对象比较一致性的关键,使用instanceof检查类型可能导致违反对称性原则,即当子类和父类都重写equals时可能出现a.equals(b)不等于b.equals(a)的情况,Lombok的@EqualsAndHashCode注解可以通过callSuper=true参数
    2024-10-10
  • java实现扫雷游戏控制台版

    java实现扫雷游戏控制台版

    这篇文章主要为大家详细介绍了java实现扫雷游戏控制台版,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • Java反射与注解的详细讲解(含代码)

    Java反射与注解的详细讲解(含代码)

    注解和反射应该说是后期JAVA开发里面比较重要的技术了,通过注解和反射可以简化许许多多的操作和步骤,最重要的是为JAVA的运行提供了更多的灵活性,这篇文章主要介绍了Java反射与注解的详细讲解,需要的朋友可以参考下
    2026-06-06
  • springboot整合JPA过程解析

    springboot整合JPA过程解析

    这篇文章主要介绍了springboot整合JPA过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • 深入理解Java原生的序列化机制

    深入理解Java原生的序列化机制

    Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。下面小编和大家来一起学习一下吧
    2019-06-06

最新评论