icode icode
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

iqqcode

保持对技术的探索实践与热爱
首页
  • Android学习

    • 📁基础内容
    • 📺AndroidCore
    • 🎨Android-UI
    • 🏖️Components
    • 📊Fragment
    • 🔗网络操作
    • 🔏异步机制
    • 📦数据存储
    • 🗃️Gradle
  • 学习笔记

    • 『框架』笔记
    • 『Kotlin』笔记
    • 《Vue》笔记
    • 《Git》学习笔记
    • 『Bug踩坑记录』
  • ListView
  • RecyclerView
  • ViewPager
  • Java笔记

    • 🟠JavaSE
    • 🟢JavaWeb
    • 🔴JavaEE
    • ⚪JavaTopic
    • 🍳设计模式
  • 计算机基础

    • 📌计算机网络
    • 🔍数据结构
    • 📦数据库
    • 💻OS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 关于

    • 📫关于我
  • 收藏

    • 网站
    • 资源
    • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaSE

  • JavaWeb

    • BootStrap

    • Cookie和Session

    • JavaScript

    • JDBC

      • JDBC实现数据库增删改查
      • JDBC资源文件配置及Druid简单使用
      • PreparedStatement
        • 1. Statement 存在的问题
          • Stetement存在SQL注入漏洞,换用PreparedStatement(预处理SQL)
        • 2. PreparedStatement执行步骤
          • PreparedStatement使用Demo
    • JQuery

    • JSON

    • JSP

    • Maven

    • Servlet

    • Tomcat

    • XML

  • JavaEE

  • JavaTopic

  • 设计模式

  • 计算机基础

  • Java后端
  • JavaWeb
  • JDBC
iqqcode
2021-06-17
目录

PreparedStatement

上一回我们通过JDBC实现数据库增删改查 (opens new window),但是还是存在一个很大的问题. 今天七夕,我们不谈感情,只谈技术

#

# 1. Statement 存在的问题

要操作的用户 username: zs password: 123

知道用户名可以直接登录通过 " - - " 注释 SQL语句

package jdbc.injection;


import org.junit.Test;

import java.sql.*;

/**
 * @Author: Mr.Q
 * @Date: 2019-08-07 11:53
 * @Description:Statement执行SQL会产生SQL注入
 */
public class SQLInjection01 {
    @Test
    public void test3() {
        try {
            // 1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2.获取连接
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc",
                            "root","1234");
            // 3.执行SQL
            String userName = "zs' --";
            String password = "fdfdfdfdf";
            String sql = "select * from user where username = '"+userName+" " +
                    "and password = '"+password+"' ";

            //知道用户名可以直接登录
            // 通过 -- 注释 SQL语句,password被注释
            // select * from user where username = 'zs' -- and password = 'fdfdfdfdf';

            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            // 遍历结果集
            if (resultSet.next()) {
                System.out.println("登录成功!");
            }else {
                System.out.println("登录失败!");
            }
            // 4.释放资源
            connection.close();
            statement.close();
            resultSet.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

在这里插入图片描述 通过 or 拆分SQL语句,一条语句变为两条

package jdbc.injection;


import org.junit.Test;

import java.sql.*;

/**
 * @Author: Mr.Q
 * @Date: 2019-08-07 11:57
 * @Description:Statement执行SQL会产生SQL注入
 */
public class SQLInjection02 {
    @Test
    public void test3() {
        try {
            // 1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2.获取连接
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc",
                    "root","1234");
            // 3.执行SQL
            String userName = "zs'or 1 = 1";
            String password = "fdfdfdfdf";
            String sql = "select * from user where username = '"+userName+" " +
                    "and password = '"+password+"' ";

            //知道用户名可以直接登录
            // 通过 or 拆分SQL语句,一条语句变为两条,password不在验证
            // select * from user where username = 'zs' or 1 = 1 and password = 'fdfdfdfdf';

            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            // 遍历结果集
            if (resultSet.next()) {
                System.out.println("登录成功!");
            }else {
                System.out.println("登录失败!");
            }
            // 4.释放资源
            connection.close();
            statement.close();
            resultSet.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

在这里插入图片描述

# Stetement存在SQL注入漏洞,换用PreparedStatement(预处理SQL)

SQL注入: 在拼接SQL时 ,有一些SQL的特殊关键字参与字符窜的拼接. 会造成安全问题

 // 3.执行 SQL
            String userName = "zs' --";
            String password = "fdfdfdfdf";
            String sql = "select * from user where username = '"+userName+" " +
                    "and password = '"+password+"' ";
1
2
3
4
5
select * from user where username = 'adkvnja' and password = 'a' or 'a' = 'a'
1

在这里插入图片描述

  • Statement 是 PreparedStatement 的父接口

  • Statement执行的是==静态==的SQL语句

    • select * from user where username = 'zs' and password = '1234'在执行SQL时时拼接好的
  • PrepareStatement执行的是==动态==的SQL语句(预编译SQL),参数使用占位符替代

    • select * from user" + " where username = ? and password = ?
  • Statement执行SQL

// Statement执行SQL

       String sql = "select * from user";
       statement = connection.createStatement();

       //查询的结果通过 ResultSet 放入到结果集中
       resultSet = statement.executeQuery(sql);
1
2
3
4
5
6
7
  • Preparement执行SQL
// Preparement执行SQL

      String userName = "zs";
      String password = "1234";
      String sql = "select * from user" + " where username = ? and password = ?";

      //预编译SQl
      PreparedStatement statement = connection.prepareStatement(sql);//传入SQL
      // 1表示对应第一个占位符
      statement.setString(1,userName);
      statement.setString(2,password);
      ResultSet resultSet = statement.executeQuery();//此时不需要传入SQL
1
2
3
4
5
6
7
8
9
10
11
12

# 2. PreparedStatement执行步骤

  • 定义SQL
    • 注意:SQL的参数使用?作为占位符. 如:select*from user where username=? and password=?
  • 获取执行SQL语句的对象
    • Preparedstatement pstmt = connection.preparestatement(String sql)//传入SQL
  • 给 ? 赋值:
    • 方法:setxxx(参数1,参数2)
    • 参数1:? 的位置编号从 1 开始
    • 参数2:? 的值
  • 执行SQL,接收返回结果,不需要传递SQL语句
    • ResultSet resultSet = statement.executeQuery();//此时不需要传入SQL

# PreparedStatement使用Demo

import org.junit.Test;

import java.sql.*;

/**
 * @Author: Mr.Q
 * @Date: 2019-07-31 16:26
 * @Description:
 */
public class JDBCDemoSelectPlus {
    @Test
    public void testSelectPlus() {
        try {
            //1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");

            //2.获取连接
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc","root","1234");

            //3.执行SQl

            String userName = "zs";
            String password = "1234";
            String sql = "select * from user" + " where username = ? and password = ?";

            //预编译SQl
            PreparedStatement statement = connection.prepareStatement(sql);
            // 1表示对应第一个占位符
            statement.setString(1,userName);
            statement.setString(2,password);
            ResultSet resultSet = statement.executeQuery();

            if(resultSet.next()) {
                System.out.println("Login Success!");
            }else {
                System.out.println("Login Failure...");
            }

            //4.释放资源
            connection.close();
            statement.close();
            resultSet.close();

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

可以看到使用PreparedStatement替代Statement之后,一样可以登录成功

在这里插入图片描述

那么,我们将密码修改为asdnvjdvb时,再次尝试登录

在这里插入图片描述

登录失败!


如果有不对的地方,欢迎指正!看到单身狗在孤独寂寞的学习,老铁能不能点个赞再走....

编辑 (opens new window)
上次更新: 2021/06/27, 10:49:09
JDBC资源文件配置及Druid简单使用
JQuary对象、选择器、DOM

← JDBC资源文件配置及Druid简单使用 JQuary对象、选择器、DOM→

最近更新
01
匿名内部类
10-08
02
函数式接口
10-08
03
ARouter-Kotlin踩坑
10-05
更多文章>
Theme by Vdoing | Copyright © 2021-2023 iqqcode | MIT License | 备案号-京ICP备2021028793号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×