一、SQL注入漏洞分析
1、分析

2、测试
public class UserDao {
/**
* 完成用户登录的方法:解决SQL注入漏洞
* @param username
* @param password
* @return
*/
public boolean login2(String username,String password){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
// 定义一个变量:
boolean flag = false;
try{
// 获得连接:
conn = JDBCUtil.getConnection();
// 编写SQL语句:
String sql = "select * from user where username = ? and password = ?";
// 预编译SQL
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setString(1, username);
pstmt.setString(2, password);
// 执行SQL语句:
rs = pstmt.executeQuery();
if(rs.next()){
// 说明根据用户名和密码可以查询到这条记录
flag = true;
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.release(rs, pstmt, conn);
}
return flag;
}
/* *//**
* 用户登录的方法
* @param username
* @param password
* @return
*/
public boolean login1(String username,String password){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
// 定义一个变量:
boolean flag = false;
try{
// 获得连接:
conn = JDBCUtil.getConnection();
// 完成登录功能:
// 创建执行SQL语句的对象:
stmt = conn.createStatement();
// 编写SQL语句:
String sql = "select * from user where username = '"+username+"' and password = '"+password+"'";
// 执行SQL:
rs = stmt.executeQuery(sql);
if(rs.next()){
// 说明根据用户名和密码可以查询到这条记录
flag = true;
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.release(rs, stmt, conn);
}
return flag;
}
}
测试类
public static void main(String[] args) {
UserDao userDao = new UserDao();
// boolean flag = userDao.login("aaa", "123");
// boolean flag = userDao.login("aaa' or '1=1", "asdfjklsd");
boolean flag = userDao.login2("aaa' -- ", "qweqwersdfsd");
if(flag){
System.out.println("登录成功!");
}else{
System.out.println("登录失败!");
}
}
3、SQL注入漏洞解决
需要采用PreparedStatement对象解决SQL注入漏洞。这个对象将SQL预先进行编译,使用?作为占位符。?所代表内容是SQL所固定。再次传入变量(包含SQL的关键字)。这个时候也不会识别这些关键字。
二、JDBC的CRUD操作之PreparedStatement的保存操作
1、代码
@Test
public void insert() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
// 获得连接:
conn = JDBCUtil.getConnection();
// 编写SQL语句:
String sql = "insert into user values (null,?,?,?,?)";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setString(1, "一");
pstmt.setString(2, "二");
pstmt.setString(3, "三");
pstmt.setInt(4, 4);
// 执行SQL
int num = pstmt.executeUpdate();
if (num > 0) {
System.out.println("保存成功!");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.release(pstmt, conn);
}
}
2、执行结果

三、修改操作
1、代码
@Test
/**
* 修改操作
*/
public void modify(){
Connection conn = null;
PreparedStatement pstmt = null;
try{
// 获得连接:
conn = JDBCUtil.getConnection();
// 编写SQL语句:
String sql = "update user set username = ?,password =?,nickname=?,age = ? where id = ?";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setString(1, "name");
pstmt.setString(2, "pwd");
pstmt.setString(3, "nick");
pstmt.setInt(4, 24);
//修改的id值
pstmt.setInt(5, 1);
// 执行SQL:
int num = pstmt.executeUpdate();
if(num > 0){
System.out.println("修改成功!");
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.release(pstmt, conn);
}
}
四、删除操作
1、代码
@Test
/**
* 删除操作
*/
public void delete(){
Connection conn = null;
PreparedStatement pstmt = null;
try{
// 获得连接:
conn = JDBCUtil.getConnection();
// 编写SQL语句:
String sql = "delete from user where id = ?";
// 预编译SQL
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setInt(1, 4);
// 执行SQL:
int num = pstmt.executeUpdate();
if(num > 0){
System.out.println("删除成功!");
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.release(pstmt, conn);
}
}
五、查询
1、代码
@Test
/**
* 查询操作
*/
public void query(){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try{
// 获得连接:
conn = JDBCUtil.getConnection();
// 编写SQL:
String sql = "select * from user";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
// 执行SQL:
rs = pstmt.executeQuery();
// 遍历结果集:
while(rs.next()){
System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password")+" "+rs.getString("nickname"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.release(rs, pstmt, conn);
}
}
六、JDBC的批处理
之前进行JDBC的操作的时候,都是一条SQL语句执行。现在如果使用批处理,可以将一批SQL一起执行。
1、代码
@Test
/**
* 批处理基本操作
*/
public void batch(){
Connection conn = null;
Statement stmt = null;
try{
// 获得连接:
conn = JDBCUtil.getConnection();
// 创建执行批处理对象:
stmt = conn.createStatement();
// 编写一批SQL语句:
String sql1 = "create database test1";
String sql2 = "use test1";
String sql3 = "create table user(id int primary key auto_increment,name varchar(20))";
String sql4 = "insert into user values (null,'aaa')";
String sql5 = "insert into user values (null,'bbb')";
String sql6 = "insert into user values (null,'ccc')";
String sql7 = "update user set name = 'tom' where id = 2";
String sql8 = "delete from user where id = 1";
// 添加到批处理
stmt.addBatch(sql1);
stmt.addBatch(sql2);
stmt.addBatch(sql3);
stmt.addBatch(sql4);
stmt.addBatch(sql5);
stmt.addBatch(sql6);
stmt.addBatch(sql7);
stmt.addBatch(sql8);
// 执行批处理:
stmt.executeBatch();
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.release(stmt, conn);
}
}
七、批量插入(使用PreparedStatement)
@Test
/**
* 批量插入记录:
* * 默认情况下MySQL批处理没有开启的,需要在url后面拼接一个参数即可。
* jdbc:mysql://localhost:3306/mydb?rewriteBatchedStatements=true
*/
public void batchInster(){
// 记录开始时间:
long begin = System.currentTimeMillis();
Connection conn = null;
PreparedStatement pstmt = null;
try{
// 获得连接:
conn = JDBCUtil.getConnection();
// 编写SQL语句:
String sql = "insert into test1.user values (null,?)";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
for(int i=1;i<=10000;i++){
pstmt.setString(1, "name"+i);
// 添加到批处理
pstmt.addBatch();
// 注意问题:
// 执行批处理
if(i % 1000 == 0){
// 执行批处理:
pstmt.executeBatch();
// 清空批处理:
pstmt.clearBatch();
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtil.release(pstmt, conn);
}
long end = System.currentTimeMillis();
System.out.println((end-begin));
}

本文深入解析SQL注入漏洞,展示如何通过PreparedStatement防止SQL注入,同时提供JDBC的CRUD操作实例,包括批量处理和批处理技巧,帮助开发者提升数据库操作的安全性和效率。
775

被折叠的 条评论
为什么被折叠?



