当前位置: 首页 > news >正文

Jdbc学习笔记(四)--PreparedStatement对象、sql攻击(安全问题)

目录

(一)使用PreparedStatement对象的原因:

使用Statement对象编写sql语句会遇到的问题

​编辑 (二)sql攻击

1.什么是sql攻击

 2.演示sql攻击

 (三)防止SQL攻击

1.PreparedStatement是什么

2. PreparedStatement的使用

​编辑 3.总结:


(一)使用PreparedStatement对象的原因:

使用Statement对象编写sql语句会遇到的问题

使用Statement对象编写sql语句,都是拼接sql

问题:

  1. 可读性差
  2. 编写复杂,容易出错
  3. 安全问题,sql攻击(sql注入)  最大问题,系统会被攻破

 (二)sql攻击

1.什么是sql攻击

      在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在登录时输入的用户名和密码都是为SQL语句的片段!

 2.演示sql攻击

首先我们需要创建一张用户表,并插入数据,用来存储用户的信息

下面我们写一个login()方法!

public static boolean login(String username, String password) {
    Connection conn=null;
    Statement stmt=null;
    ResultSet rs=null;
    try {
        Class.forName("com.mysql.jdbc.Driver");
        conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/esa?useSSL=false","root","123456");
        String sql="select count(1) num from user where username='"+username+"' and password='"+password+"'";
        System.out.println(sql);
        stmt=conn.createStatement();
        rs=stmt.executeQuery(sql);
        rs.next();
        int count=rs.getInt(1);
        return count >= 1;
    } catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
    }catch (SQLException e) {
        throw new RuntimeException(e);
    } finally {
        try{
            if (rs!=null) rs.close();
            if (stmt!=null) stmt.close();
            if (conn!=null) conn.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

细节:

throw new RuntimeException(e);  不能写成e.printStackTrace(),不然会报错,无法运行

e.printStackTrace( )是打印异常栈信息

throw new RuntimeException(e)是把异常包在一个运行时异常中抛出。

因为return count >= 1,系统会无法识别return的是一个什么值,会显示缺少return语句;

下面是调用这个方法的代码:

login("a' or '1'='1", "b' or '1'='1"); 

控制台输出登陆成功,因为是输入的用户名和密码是SQL语句片段,最终与我们的login()方法中的SQL语句组合在一起!我们来看看组合在一起的SQL语句:

select count(1)  from tb_user where username = 'a' or '1'='1' and password='b' or '1'='1'

因为 'a' or '1 = 1'这个语句,or作为关键字只要有一边返回的是true那么这个整体的值就是true,右边始终返回true,所以不管左边是否正确,这个值永远是true,那么就很容易被别人登录进去,从而造成安全问题。

 (三)防止SQL攻击

jdk中提供一个Statement的子接口,java.sql.PreparedStatement

Statement在创建时不需要传sql语句,而是把sql语句拼接起来,发送给mysql服务器

PreparedStatement是预编译的Statement,可以使用占位符?,给值占位

1.PreparedStatement是什么

PreparedStatement叫预编译声明

什么是预编译:在sql语句执行之前,要先进行两个步骤,sql编译和sql语法分析,在语句第一遍执行完毕以后,PreparedStatement会将预编译结果保存下来,在一下遇到相同的sql语句时,就不需要再重新进行一遍这三个步骤,可以跳过前两个,这也是为什么效率提高了的原因

PreparedStatement是Statement的子接口,你可以使用PreparedStatement来替换Statement。

PreparedStatement的好处:

  • 防止SQL攻击;

  • 提高代码的可读性,以可维护性;

  • 提高效率。

2. PreparedStatement的使用

  1. 使用Connection的prepareStatement(String sql):即创建它时就让它与一条SQL模板绑定;

  2. 调用PreparedStatement的setXXX()系列方法为问号设置值

  3. 调用executeUpdate()或executeQuery()方法,但要注意,调用没有参数的方法;

接下来我们来进行演示:

对之前的代码进行修改:

1.将拼接的username和password换成?

2.创建PreparedStatement对象,将Statement改成PreparedStatement

3.因为PreparedStatement的executeQuery()和executeUpdate()方法是无参的,所以要将括号中的sql删除

4.给?赋值

PreparedStatement提供了一组setXxx(int  问号的索引,值)方法,问号索引从1开始

如果不知道列的数据类型,有一个通用数据类型:setObject()

代码: 

public static boolean login2(String username, String password) {
    Connection conn=null;
    PreparedStatement stmt=null;
    ResultSet rs=null;
    try {
        Class.forName("com.mysql.jdbc.Driver");
        conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/esa?useSSL=false","root","123456");
        String sql="select count(1) num from tb_user where username = ? and password= ?";
        System.out.println(sql);
        stmt = conn.prepareStatement(sql);
        //----------------
        //给?赋值
        //----------------
        stmt.setString(1,username);
        stmt.setString(2,password);
        rs=stmt.executeQuery();
        rs.next();
        int count=rs.getInt(1);
        return count >= 1;
    } catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
    }catch (SQLException e) {
        throw new RuntimeException(e);
    } finally {
        try{
            if (rs != null) rs.close();
            if (stmt != null) stmt.close();
            if (conn != null) conn.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

执行结果:

登录失败!!,防止sql攻击成功

 3.总结:

 所以,建议大家在今后的开发中,无论什么情况,都去需要PreparedStatement,而不是使用Statement。  


http://www.mrgr.cn/news/75164.html

相关文章:

  • 多摩川编码器协议及单片机使用
  • 低速接口项目之串口Uart开发(七)——如何在FPGA项目中实现自适应波特率串口功能
  • Android仿前端分页组件pagination
  • 移动语义和拷贝语义有什么区别?
  • java集合练习题
  • SpringBoot多环境+docker集成企业微信会话存档sdk
  • 联丰策略炒股股票交易市场券商股,盘中突然拉升
  • 25京考考试时间已确定,速速查收!
  • 时序论文19|ICML24 : 一篇很好的时序模型轻量化文章,用1k参数进行长时预测
  • Linux系统编程多线程之条件变量和信号量讲解
  • java八股-垃圾回收机制-垃圾回收算法,分代回收,垃圾回收器
  • 精灵图(十八课)
  • RHCE web解析、dns配置、firewalld配置实验
  • 人工智能技术的发展历程和现状
  • 基于Spring Boot+Vue的多媒体素材管理系统的设计与实现
  • 多模态Embedding不愧是CVPR和NIPS的共同选择!这发文思路真的需要好好学习一下!
  • c语言学习16按键控制流水灯
  • 闯关leetcode——3178. Find the Child Who Has the Ball After K Seconds
  • docker安装到D盘
  • 游戏引擎学习第11天
  • 易考八股文之代理模式在AOP中如何应用?
  • Gartner发布XDR扩展检测和响应市场指南:XDR需要具备的19项功能
  • 逆向攻防世界CTF系列31-elrond32
  • 代码随想录算法训练营第46天 | 647. 回文子串、516.最长回文子序列
  • curl 安装最新版
  • 如何在手机上完整下载B站视频并保存到相册?