前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >6. 使用 JDBC 完成登录案例 以及 SQL 注入问题

6. 使用 JDBC 完成登录案例 以及 SQL 注入问题

作者头像
Devops海洋的渔夫
发布2022-01-17 14:50:11
3860
发布2022-01-17 14:50:11
举报
文章被收录于专栏:Devops专栏

6. 使用 JDBC 完成登录案例 以及 SQL 注入问题

前言

在前面的章节中,我们已经学会了使用 statement 来执行数据库的 增删查改 的操作,并且封装一个 JDBC 工具类,实现了数据库连接获取,以及资源关闭的方法。

下面我们来使用 statement 来实现一个简单的用户登录案例,并且引出一个 SQL 注入的问题。

案例-登录案例

1.需求

在控制台输入用户名和密码,查询数据库,如果数据库存在当前用户,显示登录成功!

如果数据库不存在当前用户,显示登录失败!

2分析

2.1登录是做什么
  • 登录说白了就是根据用户名和密码查询数据库, 如果能查询出来就是登录成功, 查询不出来就是登录失败
2.2思路分析

3.代码实现

3.1 那么首先我们需要准备前面篇章生成的 mysql 数据,如下:
代码语言:javascript
复制
mysql> select * from t_user;
+----+-------+------+------+
| id | uname | age  | sex  |
+----+-------+------+------+
|  1 | zs    |   18 |    1 |
|  2 | ls    |   20 |    0 |
|  3 | ww    |   23 |    1 |
|  4 | zl    |   24 |    1 |
|  5 | lq    |   15 |    0 |
|  6 | hh    |   12 |    0 |
|  7 | wzx   |   60 | NULL |
|  8 | lb    | NULL | NULL |
+----+-------+------+------+
8 rows in set (0.00 sec)

mysql> 
3.2 准备上一篇章封装好的 JdbcUtil 工具类
  • 创建配置文件,配置文件在resources目录下,并且要将resources目录标记为资源文件的根路径,扩展名是properties

配置文件:

代码语言:javascript
复制
jdbc.username=root
jdbc.password=Li********密码**********0
jdbc.url=jdbc:mysql://localhost:3306/testdb?rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false
jdbc.driverClass=com.mysql.jdbc.Driver
  • 工具类如下:
代码语言:javascript
复制
package com.utils;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
import java.util.ResourceBundle;

/**
 *
 * @Description:JdbcUtils 工具类
 * 1.抽取: 复用重复的代码
 *      方式: 把重复代码抽取到父类, 把公共代码抽取成方法, 把公共代码抽取到工具类
 *      原则: 抽取重复的
 * 2.选择把公共代码抽取到工具类
 *      找重复的: (1,2 -- 获得连接的方法), (5-- 释放资源的方法)
 *   思路:
 *      定义一个类
 *      在这个类里面定义两个方法
 * 3. 工具类优化
 *      把四个参数(驱动,路径,用户名,密码)抽取成 jdbc.properties
 *      在static{}里面读取jdbc.properties, 给变量赋值
 *
 * @author Aron.li
 * @date 2021/1/20 7:59
 */
public class JdbcUtils {

    private static String driverClass;
    private static String url;
    private static String username;
    private static String password;

    //驱动只需要注册一次,把注册驱动的代码放在静态代码块
    static {
        //静态代码块就会在类加载的时候执行
        try {
            //读取jdbc.properties配置文件中的内容
            //1. 将配置文件转换成字节输入流,使用类加载器
            InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            //2. 创建一个Properties对象
            Properties properties = new Properties();
            //3. properties对象加载配置文件
            properties.load(is);

            //4.调用properties的方法,根据key获取值
            username = properties.getProperty("jdbc.username");
            password = properties.getProperty("jdbc.password");
            url = properties.getProperty("jdbc.url");
            driverClass = properties.getProperty("jdbc.driverClass");

            //5.注册驱动
            Class.forName(driverClass);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 获得连接
     *
     */
    public static Connection getConnection() {
        //2. 获得连接
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage()); // 抛出运行时异常
        }
        return connection;
    }

    /**
     * 释放资源
     *
     * @param resultSet
     * @param statement
     * @param connection
     */
    public static void closeAll(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }

            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage()); // 抛出运行时异常
        }

    }

    public static void closeAll(Statement statement, Connection connection) throws SQLException {
        closeAll(null, statement, connection);
    }

}
3.3 创建登录测试类 LoginClient
代码语言:javascript
复制
public class LoginClient {

    /**
     * 使用 JDBC 实现登录案例
     */
    public static void main(String[] args) throws SQLException {

        //1. 获取用户输入的 用户名
        System.out.println("请输入的用户名: ");
        Scanner scanner = new Scanner(System.in);
        String username = scanner.nextLine();
        System.out.println("输入的用户名: " + username);

        //2. 获取数据库连接
        Connection connection = JdbcUtils.getConnection();

        //3. 根据用户名执行数据查询
        String sql = "select * from t_user where uname = '" + username + "'"; // 设置SQL
        Statement statement = connection.createStatement(); // 获取statement
        ResultSet resultSet = statement.executeQuery(sql); // 执行查询SQL

        //4. 如果查询存在用户名的数据,那么则登录成功;反之,登录失败
        if (resultSet.next()) {
            System.out.println("登录成功");
        } else {
            System.out.println("登录失败");
        }
    }

}
3.4 执行测试登录如下:

4.小结

4.1登录思路
  • 登录说白了就是根据用户名和密码查询数据库
  • 登录思路
    • 登录成功 打印 '登录成功'
    • 登录失败 打印 登录失败'
    • 获得用户输入的用户名和密码
    • 使用Jdbc根据用户名和密码查询数据库 封装成User对象
    • 判断是否登录成功(判断User是否为null)

5.使用 statement 执行SQL,则会出现 SQL 注入的问题

5.1 SQL注入问题出现

当输入的密码 ' or '' = ' , 发现永远登录成功.

  • 下面我们首先演示查询一个不存在的用户名,登录失败的情况,如下:
  • 然后拼接 ' or '' = ' 字符串,将会登录成功
5.2 SQL注入问题分析
  • 输入的密码 ' or '' = ', 语句如下
代码语言:javascript
复制
-- 当查询 hello 的用户名,则会查询无数据
mysql> select * from t_user where uname = 'hello';
Empty set (0.00 sec)
-- 当在查询条件后面加上 or '' = '' ,那么则可以查询出所有数据
mysql> select * from t_user where uname = 'hello' or '' = '';
+----+-------+------+------+
| id | uname | age  | sex  |
+----+-------+------+------+
|  1 | zs    |   18 |    1 |
|  2 | ls    |   20 |    0 |
|  3 | ww    |   23 |    1 |
|  4 | zl    |   24 |    1 |
|  5 | lq    |   15 |    0 |
|  6 | hh    |   12 |    0 |
|  7 | wzx   |   60 | NULL |
|  8 | lb    | NULL | NULL |
+----+-------+------+------+
8 rows in set (0.00 sec)

mysql> 

相似会出现问题的SQL 如下:

代码语言:javascript
复制
select * from t_user where uname = 'hello' or '' = '';
select * from t_user where uname = 'hello' or true;
select * from t_user where  true;
select * from t_user;
  • 发现语句出现了sql注入问题 这是因为 statement 在使用拼接 sql 字符串的时候, 把用户输入的 or 当成关键词注入到了sql语句里面了。 那么该怎么解决这个问题呢?我们将会在下一个章节,使用 preparedStatement 解决 SQL 注入的问题。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 海洋的渔夫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 6. 使用 JDBC 完成登录案例 以及 SQL 注入问题
    • 前言
      • 案例-登录案例
        • 1.需求
        • 2分析
        • 3.代码实现
        • 4.小结
        • 5.使用 statement 执行SQL,则会出现 SQL 注入的问题
    相关产品与服务
    数据库
    云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档