JDBC 【SQL注入】

news2024/11/18 7:44:39

一、SQL注入🍓

(一)、SQL注入问题🥝

1.向jdbc_user表中 插入两条数据

# 插入2条数据 
INSERT INTO jdbc_user VALUES(NULL,'jack','123456','2020/2/24'); 
INSERT INTO jdbc_user VALUES(NULL,'tom','123456','2020/2/24');

2.SQL注入演示

# SQL注入演示 -- 填写一个错误的密码 
SELECT * FROM jdbc_user 
WHERE username = 'tom' AND PASSWORD = '123' OR '1' = '1';

如果这是一个登陆操作,那么用户就登陆成功了.显然这不是我们想要看到的结果

(二)、注入案例:用户登陆🥝

需求:
用户在控制台上输入用户名和密码, 然后使用 Statement 字符串拼接的方式 实现用户的登录

步骤

  1. 得到用户从控制台上输入的用户名和密码来查询数据库
  2. 写一个登录的方法
    a) 通过工具类得到连接
    b) 创建语句对象,使用拼接字符串的方式生成 SQL 语句
    c) 查询数据库,如果有记录则表示登录成功,否则登录失败
    d) 释放资源
Sql注入方式: 123' or '1'='1

代码示例

public class TestLogin01 { 
/**
* 用户登录案例 
* 使用 Statement字符串拼接的方式完成查询 
* @param args 
*/ 
public static void main(String[] args) throws SQLException { 
//1.获取连接 
Connection connection = JDBCUtils.getConnection(); 
//2.获取Statement 
Statement statement = connection.createStatement(); 
//3.获取用户输入的用户名和密码 
Scanner sc = new Scanner(System.in); 
System.out.println("请输入用户名: "); 
String name = sc.nextLine(); 
System.out.println("请输入密码: "); 
String pass = sc.nextLine(); 
System.out.println(pass); 
//4.拼接Sql,执行查询
// String pass = "xxx' or '1'='1"; xxx' or '1' = '1
String sql = "select * from jdbc_user " + "where username = " + " '" + name +"' " +" and password = " +" '" + pass +"'"; 
System.out.println(sql); 
ResultSet resultSet = statement.executeQuery(sql); 
//5.处理结果集,判断结果集是否为空 
if(resultSet.next()){ 
	System.out.println("登录成功! 欢迎您: " + name); 
}else { 
	System.out.println("登录失败!"); 
}
//释放资源 
JDBCUtils.close(connection,statement,resultSet); 
} 
}

问题分析:

  1. 什么是SQL注入?
    我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了 原有SQL 真正的意义,以上问题称为 SQL 注入 .
  2. 如何实现的注入
    根据用户输入的数据,拼接处的字符串
select * from jdbc_user 
where username = 'abc' and password = 'abc' or '1'='1' 

name='abc' and password='abc' 为假 '1'='1' 真 
相当于 select * from user where true=true; 查询了所有记录

如何解决
要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进行简单的字符串拼接

(三)、 预处理对象🥝

  1. PreparedStatement 接口介绍
    PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句对象.
    预编译: 是指SQL 语句被预编译,并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。

  2. PreparedStatement 特点
    因为有预先编译的功能,提高 SQL 的执行效率。
    可以有效的防止 SQL 注入的问题,安全性更高

  3. 获取PreparedStatement对象
    通过Connection创建PreparedStatement对象

在这里插入图片描述

  1. PreparedStatement接口常用方法
    在这里插入图片描述

  2. 使用PreparedStatement的步骤

  • 编写 SQL 语句,未知内容使用?占位:
"SELECT * FROM jdbc_user WHERE username=? AND password=?";
  • 获得 PreparedStatement 对象
  • 设置实际参数:setXxx( 占位符的位置, 真实的值)
  • 执行参数化 SQL 语句
  • 关闭资源
    在这里插入图片描述

二、使用PreparedStatement完成登录案例🍓

使用 PreparedStatement 预处理对象,可以有效的避免SQL注入

步骤:
1.获取数据库连接对象
2.编写SQL 使用? 占位符方式
3.获取预处理对象 (预编译对象会将Sql发送给数据库 进行预编译)
4.提示用户输入用户名 & 密码
5.设置实际参数:setXxx(占位符的位置, 真实的值)
6.执行查询获取结果集
7.判断是否查询到数据
8.关闭资源

/*** 使用预编译对象 PrepareStatement 完成登录案例 * @param args * @throws SQLException */ 
public static void main(String[] args) throws SQLException { 
//1.获取连接 
Connection connection = JDBCUtils.getConnection(); 
//2.获取Statement 
Statement statement = connection.createStatement(); 
//3.获取用户输入的用户名和密码
Scanner sc = new Scanner(System.in); 
System.out.println("请输入用户名: "); 
String name = sc.nextLine(); 
System.out.println("请输入密码: "); 
String pass = sc.nextLine(); 
System.out.println(pass); 
//4.获取 PrepareStatement 预编译对象 
//4.1 编写SQL 使用 ? 占位符方式 
String sql = "select * from jdbc_user where username = ? and password = ?"; 
PreparedStatement ps = connection.prepareStatement(sql); 
//4.2 设置占位符参数 
ps.setString(1,name); 
ps.setString(2,pass); 
//5. 执行查询 处理结果集 
ResultSet resultSet = ps.executeQuery(); 
if(resultSet.next()){ 
	System.out.println("登录成功! 欢迎您: " + name); 
}else{
	System.out.println("登录失败!"); 
}
//6.释放资源 
JDBCUtils.close(connection,statement,resultSet); 
} 

(一)、PreparedStatement的执行原理🥝

分别使用 Statement对象 和 PreparedStatement对象进行插入操作

public static void main(String[] args) throws SQLException { 
Connection con = JDBCUtils.getConnection(); 
//获取 Sql语句执行对象 
Statement st = con.createStatement(); 
//插入两条数据 
st.executeUpdate("insert into jdbc_user values(null,'张三','123','1992/12/26')"); 
st.executeUpdate("insert into jdbc_user values(null,'李四','123','1992/12/26')");

//获取预处理对象 
PreparedStatement ps = con.prepareStatement("insert into jdbc_user values(?,?,?,?)"); 
//第一条数 设置占位符对应的参数 
ps.setString(1,null); 
ps.setString(2,"hd"); 
ps.setString(3,"qwer"); 
ps.setString(4,"2000/1/10"); 
//执行插入 
ps.executeUpdate(); 
//第二条数据 
ps.setString(1,null); 
ps.setString(2,"jc"); 
ps.setString(3,"1122"); 
ps.setString(4,"2000/1/10"); 
//执行插入 
ps.executeUpdate(); 
//释放资源 
st.close(); 
ps.close(); 
con.close(); 
} 

在这里插入图片描述

(二)、 Statement 与 PreparedStatement的区别?🥝

  1. Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句。
  2. PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数值。
  3. PrepareStatement可以减少编译次数提高数据库性能。

三、JDBC 控制事务🍓

之前我们是使用 MySQL 的命令来操作事务。接下来我们使用 JDBC 来操作银行转账的事务。

(一)、数据准备🥝

-- 创建账户表 
CREATE TABLE account( 
	-- 主键 
	id INT PRIMARY KEY AUTO_INCREMENT, 
	-- 姓名 
	NAME VARCHAR(10), 
	-- 转账金额 
	money DOUBLE 
);

-- 添加两个用户 
INSERT INTO account (NAME, money) VALUES ('tom', 1000), ('jack', 1000);

(二)、事务相关API🥝

在这里插入图片描述

(三)、 开发步骤🥝

  1. 获取连接
  2. 开启事务
  3. 获取到 PreparedStatement , 执行两次更新操作
  4. 正常情况下提交事务
  5. 出现异常回滚事务
  6. 最后关闭资源
//JDBC 操作事务 
public static void main(String[] args) { 
Connection con = null; 
PreparedStatement ps = null; 
try {
	//1. 获取连接 
	con = JDBCUtils.getConnection(); 
	//2. 开启事务 
	con.setAutoCommit(false); 
	//3. 获取到 PreparedStatement 执行两次更新操作 
	//3.1 tom 账户 -500 
	ps = con.prepareStatement("update account set money = money - ? where name = ? "); 
	ps.setDouble(1,500.0); 
	ps.setString(2,"tom"); 
	ps.executeUpdate(); 
	//模拟tom转账后 出现异常 
	System.out.println(1 / 0); 
	//3.2 jack 账户 +500 
	ps = con.prepareStatement("update account set money = money + ? where name = ? "); 
	ps.setDouble(1,500.0); 
	ps.setString(2,"jack"); 
	ps.executeUpdate(); 
	//4. 正常情况下提交事务 
	con.commit(); 
	System.out.println("转账成功!"); 
} catch (SQLException e) { 
	e.printStackTrace(); 
	try {
		//5. 出现异常回滚事务 
		con.rollback(); 
	} catch (SQLException ex) { 
		ex.printStackTrace(); 
	} 
} finally { 
	//6. 最后关闭资源 
	JDBCUtils.close(con,ps); 
} 
} 

四、数据库连接池🍓

连接池介绍

什么是连接池

实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们 采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池.

连接池的好处
用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。

Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!

常见的连接池有 DBCP连接池, C3P0连接池, Druid连接池, 接下里我们就详细学习一下

(一)、 数据准备🥝

#创建数据库 
CREATE DATABASE db5 CHARACTER SET utf8; 
#使用数据库 
USE db5; 
#创建员工表 
CREATE TABLE employee ( 
	eid INT PRIMARY KEY AUTO_INCREMENT , 
	ename VARCHAR (20), -- 员工姓名 
	age INT , -- 员工年龄 
	sex VARCHAR (6), -- 员工性别 
	salary DOUBLE , -- 薪水 
	empdate DATE -- 入职日期 
);

# 插入数据 
INSERT INTO employee (eid, ename, age, sex, salary, empdate) VALUES(NULL,'李清照',22,'女',4000,'2018-11-12'); 
INSERT INTO employee (eid, ename, age, sex, salary, empdate) VALUES(NULL,'林黛玉',20,'女',5000,'2019-03-14'); 
INSERT INTO employee (eid, ename, age, sex, salary, empdate) VALUES(NULL,'杜甫',40,'男',6000,'2020-01-01'); 
INSERT INTO employee (eid, ename, age, sex, salary, empdate) VALUES(NULL,'李白',25,'男',3000,'2017-10-01');


Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。

使用
导入 jar包 配置文件

在这里插入图片描述

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true&characterEncoding=utf-8
username=root
password=123456
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000

(二)、 编写Druid工具类🥝

获取数据库连接池对象
通过工厂来来获取 DruidDataSourceFactory类的createDataSource方法createDataSource(Properties p) 方法参数可以是一个属性集对象

public class DruidUtils { 
	//1.定义成员变量 
	public static DataSource dataSource; 
	//2.静态代码块 
	static{ 
		try {
			//3.创建属性集对象 
			Properties p = new Properties(); 
			//4.加载配置文件 Druid 连接池不能够主动加载配置文件 ,需要指定文件 
			InputStream inputStream = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"); 
			//5. 使用Properties对象的 load方法 从字节流中读取配置信息 
			p.load(inputStream); 
			//6. 通过工厂类获取连接池对象 
			dataSource = DruidDataSourceFactory.createDataSource(p); 
		} catch (Exception e) { 
			e.printStackTrace(); 
		} 
	}
	
	//获取连接的方法 
	public static Connection getConnection(){ 
		try {
			return dataSource.getConnection(); 
		} catch (SQLException e) { 
			e.printStackTrace(); 
			return null; 
		} 
	}
	//释放资源 
	public static void close(Connection con, Statement statement){ 
		if(con != null && statement != null){ 
			try {
				statement.close(); 
				//归还连接 
				con.close(); 
			} catch (SQLException e) { 
				e.printStackTrace(); 
			} 
		} 
	}
	public static void close(Connection con, Statement statement, ResultSet resultSet){ 
		if(con != null && statement != null && resultSet != null){ 
			try {
				resultSet.close(); 
				statement.close(); 
				//归还连接 
				con.close(); 
			} catch (SQLException e) { 
				e.printStackTrace(); 
			} 
		} 
	} 
}

(三)、 测试工具类🥝

需求: 查询薪资在3000 - 5000元之间的员工姓名

// 需求 查询 薪资在3000 到 5000之间的员工的姓名 
public static void main(String[] args) throws SQLException { 
//1.获取连接 
Connection con = DruidUtils.getConnection(); 
//2.获取Statement对象 
Statement statement = con.createStatement(); 
//3.执行查询 
ResultSet resultSet = statement.executeQuery("select ename from employee where salary between 3000 and 5000"); 
//4.处理结果集 
while(resultSet.next()){ 
	String ename = resultSet.getString("ename"); 
	System.out.println(ename); 
}
//5.释放资源 
DruidUtils.close(con,statement,resultSet); 
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1065243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

泊车功能专题介绍 ———— AVP系统基础数据交互内容

文章目录 系统架构系统功能描述云端子系统车辆子系统场端子系统用户APP 工作流程基础数据交互内容AVP 系统基础数据交互服务车/用户 - 云基础数据交互内容车位查询工作流程技术要求数据交互要求 车位预约工作流程技术要求数据交互要求 取消预约工作流程技术要求数据交互要求 泊…

利用C++开发一个迷你的英文单词录入和测试小程序-升级版本

我们现在有了一个本地sqlite3的迷你英文单词小测试工具,需求就跟工作当中一样是不断变更的。这里虚构两个场景,并且一步一步的完成最终升级后的小demo。 场景:数据不依赖本地sqlite3,需要支持远程访问,用目前的restfu…

深入探究C++编程中的资源泄漏问题

目录 1、GDI对象泄漏 1.1、何为GDI资源泄漏? 1.2、使用GDIView工具排查GDI对象泄漏 1.3、有时可能需要结合其他方法去排查 1.4、如何保证没有GDI对象泄漏? 2、进程句柄泄漏 2.1、何为进程句柄泄漏? 2.2、创建线程时的线程句柄泄漏 …

Dijkstra 邻接表表示算法 | 贪心算法实现--附C++/JAVA实现源码

以下是详细步骤。 创建大小为 V 的最小堆,其中 V 是给定图中的顶点数。最小堆的每个节点包含顶点编号和顶点的距离值。 以源顶点为根初始化最小堆(分配给源顶点的距离值为0)。分配给所有其他顶点的距离值为 INF(无限)。 当最小堆不为空时,执行以下操作: 从最小堆中提取…

JVM技术文档--JVM诊断调优工具Arthas--阿里巴巴开源工具--一文搞懂Arthas--快速上手--国庆开卷!!

​ Arthas首页 简介 | arthas Arthas官网文档 Arthas首页、文档和下载 - 开源 Java 诊断工具 - OSCHINA - 中文开源技术交流社区 阿丹: 之前聊过了一些关于JMV中的分区等等,但是有同学还是在后台问我,还有私信问我,学了这些…

人工智能驱动的古彝文识别:保护和传承古彝文文化

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

从零开始 Spring Cloud 13:分布式事务

从零开始 Spring Cloud 13:分布式事务 1.分布式事务问题 用一个示例项目演示在分布式系统中使用事务会产生的问题。 示例项目的 SQL:seata_demo.sql 示例项目代码:seata-demo.zip 这个示例项目中的微服务的互相调用依赖于 Nacos&#xf…

低代码平台如何借助Nginx实现网关服务

摘要:本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 前言 在典型的系统部署架构中,应用服务器是一种软件或硬件系统&#xff0c…

解决Ubuntu18.04安装好搜狗输入法后无法打出中文的问题

首先下载安装 搜狗拼音输入法 ,下载选择: x86_64 在ubuntu中设置 fcitx 最后发现安装好了,图标有了 ,但是使用时不能输入中文,使用下面的命令解决: sudo apt install libqt5qml5 libqt5quick5 libqt5qu…

PyTorch深度学习实战(20)——从零开始实现R-CNN目标检测

PyTorch深度学习实战(20)——从零开始实现R-CNN目标检测 0. 前言1. R-CNN 目标检测模型1.1 核心思想1.2 算法流程 2. 实现 R-CNN 目标检测2.1 数据集准备2.2 获取区域提议和偏移量2.3 创建训练数据2.4 构建 R-CNN 架构 3. R-CNN目标检测模型测试小结系列…

【JUC系列-09】深入理解ReentrantReadWriteLock的底层实现

JUC系列整体栏目 内容链接地址【一】深入理解JMM内存模型的底层实现原理https://zhenghuisheng.blog.csdn.net/article/details/132400429【二】深入理解CAS底层原理和基本使用https://blog.csdn.net/zhenghuishengq/article/details/132478786【三】熟练掌握Atomic原子系列基本…

浅谈智能安全配电装置在老年人建筑中的应用

摘要:我国每年因触电伤亡人数非常多,大多数事故是发生在用电设备和配电装置。在电气事故中,无法预料和不可抗拒的事故是比较少的,大量用电事故可采取切实可行措施来预防。本文通过结合老年人建筑的特点和智能安全配电装置的功能&a…

教你三步搞定VsCode调试C++

目录 1 配置编译任务2 配置调试任务3 进行调试 1 配置编译任务 使用VsCode进行C开发时,除了在机器上安装必要的编译工具(例如,gcc、g、cmake等)之外,还需要在VsCode配置编译任务,从而可以通过点击或者快捷…

【MySql】mysql之进阶查询语句

目录 一、常用查询 1、order by按关键字排序❤ 1.1 升序排序 1.2 降序排序 1.3 结合where进项条件过滤再排序 1.4 多字段排序 2、and和or判断 2.1 and和or的使用 2.2 嵌套、多条件使用 3、distinct 查询不重复记录 4、group by 对结果进行分组 5、limit限制结果…

MySQL57部署与配置[Windows10]

下载原始安装包 https://dev.mysql.com/downloads/installer/https://downloads.mysql.com/archives/notifier/默认安装 MySQL57 默认安装 MySQL Notifier 环境变量配置 Path: C:\Program Files\MySQL\MySQL Server 5.7\binDBeaver数据库连接

【MySql】4- 实践篇(二)

文章目录 1. SQL 语句为什么变“慢”了1.1 什么情况会引发数据库的 flush 过程呢?1.2 四种情况性能分析1.3 InnoDB 刷脏页的控制策略 2. 数据库表的空间回收2.1 innodb_file_per_table参数2.2 数据删除流程2.3 重建表2.4 Online 和 inplace 3. count(*) 语句怎样实现…

websocket拦截

python实现websocket拦截 前言一、拦截的优缺点优点缺点二、实现方法1.环境配置2.代码三、总结现在的直播间都是走的websocket通信,想要获取websocket通信的内容就需要使用websocket拦截,大多数是使用中间人代理进行拦截,这里将会使用更简单的方式进行拦截。 前言 开发者工…

RK3568平台开发系列讲解(外设篇)AP3216C 三合一环境传感器驱动

🚀返回专栏总目录 文章目录 一、AP3216C 简介二、AP3216C驱动程序2.1、设备树修改2.2、驱动程序沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在本篇将介绍AP3216C 三合一环境传感器的驱动。 一、AP3216C 简介 AP3216C 是由敦南科技推出的一款传感器,其支持环境光…

OpenWrt使用Privoxy插件修改UA

OpenWrt使用privoxy修改UA 1.安装privoxy插件 SSH连接到路由器 更新插件列表 update opkg安装插件 opkg install privoxy luci-app-privoxy luci-i18n-privoxy-zh-cn重启路由器 2.配置privoxy 打开配置页面 文件和目录 访问和控制 转发 杂项 日志 编辑配置 浏览器打开 …

Kaggle - LLM Science Exam(一):赛事概述、数据收集、BERT Baseline

文章目录 一、赛事概述1.1 OpenBookQA Dataset1.2 比赛背景1.3 评估方法和代码要求1.4 比赛数据集1.5 优秀notebook 二、BERT Baseline2.1 数据预处理2.2 定义data_collator2.3 加载模型,配置trainer并训练2.4 预测结果并提交2.5 deberta-v3-large 1k Wiki&#xff…