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.mzph.cn/pingmian/60968.shtml

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

相关文章

后端分层解耦

引入 在上篇所举的例子中,我们将所有的代码均放在HelloControl方法之中,这样会导致代码的复用性、可读性较差,难以维护。因此我们需 三层架构 在之前的代码中,代码大体可以分为三部分:数据访问、数据逻辑处理、响应数…

97.【C语言】数据结构之栈

目录 栈 1.基本概念 2.提炼要点 3.概念选择题 4.栈的实现 栈初始化函数 入栈函数 出栈函数和栈顶函数 栈顶函数 栈销毁函数 栈 基本概念参见王爽老师的《汇编语言 第四版》第56和57页 节选一部分 1.基本概念 注意:这里提到的数据结构中的栈有别于操作系统的栈,后者是…

初识算法 · 模拟(1)

目录 前言: 替换所有的问号 题目解析 算法原理 算法编写 提莫攻击 题目解析 算法原理 算法编写 外观数列 题目解析 算法原理 算法编写 前言: ​本文的主题是模拟,通过三道题目讲解,一道是提莫攻击,一道是…

【数值分析】高斯-赛德尔方法、规范化幂法、原点移位法

【数值分析】高斯-赛德尔方法、规范化幂法、原点移位法 题目 要求 代码实现过程不能调用任何库函数自带的“线性 方程组求解、特征值求解库函数” 利用高斯-赛德尔方法求解上述线性方程组 使用Python编程求解矩阵A与列向量b import numpy as np import sympy as spdef crea…

【CUDA】了解GPU架构

目录 一、初步认识 二、Fermi架构 三、Kepler 架构 3.1 动态并行 3.2 Hyper-Q 一、初步认识 SM(Streaming Multiprocessors)是GPU架构中非常重要的部分,GPU硬件的并行性就是由SM决定的。以Fermi架构为例,其包含以下主要组成…

64位程序调用32位dll解决方案

最近在做64位代码移植,发现很多老代码使用到了第三方的32位dll;而且这些第三方32位dll库已经年代久远,原开发商已不再了;所以急切的需要在64位主程序 中使用老的32位dll;查询很多解决方案 发现目前只有使用com 进程外组件的方法可以解决此问题…

【HOT100第五天】搜索二维矩阵 II,相交链表,反转链表,回文链表

240.搜索二维矩阵 II 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 先动手写写最简单方法,二重循环。 class Solution { public:bool searchMa…

模板元函数应用:输出字符串。

看下面三个字符串,s1,s2,s3 : string s1 "逆天邪神";wstring s2 _t("焚星妖莲");_string s3 "焚绝尘"; 在控制台输出字符串,可能的一个方案是: void print_test(const wstring& s) {std::…

pytest | 框架的简单使用

这里写目录标题 单个文件测试方法执行测试套件的子集测试名称的子字符串根据应用的标记进行选择 其他常见的测试命令 pytest框架的使用示例 pytest将运行当前目录及其子目录中test_*.py或 *_test.py 形式的所有 文件 文件内的函数名称可以test* 或者test_* 开头 单个文件测试…

【C++】类和对象-深度剖析默认成员函数-上

> 🍃 本系列为初阶C的内容,如果感兴趣,欢迎订阅🚩 > 🎊个人主页:[小编的个人主页])小编的个人主页 > 🎀 🎉欢迎大家点赞👍收藏⭐文章 > ✌️ 🤞 &#x1…

Web性能优化:从基础到高级

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 Web性能优化:从基础到高级 Web性能优化:从基础到高级 Web性能优化:从基础到高级 引言 基础优…

当 docker-compose.yaml 文件部署时,Dify 线上版本升级过程

如果线上 Dify 是通过 docker-compose.yaml 文件部署的,那么当 Dify 版本升级时该如何操作呢?官方已经给出了 Docker compose 和 Source Code 两种方式。相对而言,前者更简单些,至少不需要安装依赖包和迁移数据库文件。为了更加具…

如何让手机ip变成动态

在数字化浪潮中,手机已成为我们日常生活中不可或缺的一部分。无论是浏览网页、使用社交媒体还是进行在线购物,手机都扮演着举足轻重的角色。然而,在享受网络带来的便利时,我们也需要关注网络安全和隐私保护。静态IP地址可能让手机…

vue3 如何调用第三方npm包内部的 pinia 状态管理库方法

抛砖引玉: 如果在开发vue3项目是, 引用了npm第三方包 ,而且这个包内使用了Pinia 状态管理库,那我们如何去调用 npm内部的 Pinia 状态管理库呢? 实际遇到的问题: 今天在制作npm包时遇到的问题,之前Vue2版本的时候状态管理库用的Vuex ,当时调用npm包内的状态管理库很简单,直接引…

Linux笔记---调试工具GDB(gdb)

1. gdb的概念 GDB,全称GNU Debugger,是一个功能强大的开源调试工具,广泛用于Unix和类Unix系统,以及Microsoft Windows和macOS平台。GDB允许开发者在程序执行过程中查看内部运行情况,帮助定位和修复程序中的错误。 gd…

编译器gcc/g++

gcc 只用来编译C g 编译C/C 1.预处理(进行宏替换/去注释/条件编译/头文件展开等) 先创建 code.c 文件 -E --> 从现在开始,进行程序的翻译,一旦预处理做完,就停下来 -o --> 表明 -o 后面的文件名称 code…

一.安装版本为19c的Oracle数据库管理系统(Oracle系列)

1.数据库版本信息: 版本信息: 或者直接由命令查出来: 2.操作系统的版本信息 3.安装包下载与上传 可以去oracle官网下载也可以从其他人的百度网盘链接中下载: 使用xftp工具或者其他的工具(mobaxterm)上传到l…

DimensionX 部署笔记

目录 生成视频用CogVideoX-5b-I2V 推理代码: DimensionX 生成视频用CogVideoX-5b-I2V 推理代码: 可以生成,从左向右旋转的,也可以生成从上往下旋转的: import torch from diffusers import CogVideoXImageToVideo…

uni-app移动端与PC端兼容预览PDF文件

过程遇到的问题 1、如果用的是最新的版本的pdfjs的话,就会报Promise.withResolvers 不是一个方法的错误,原因是Promise.withResolvers是ES15新特性,想了解可参考链接,这里的解决方案是将插件里的涉及到Promise.withResolvers的地…

Node.js | Yarn下载安装与环境配置

一、安装Node.js Yarn 是 Node.js 下的包管理工具,因此想要使用 Yarn 就必须先下载 Node.js。 推荐参考:Node.js | npm下载安装及环境配置教程 二、Yarn安装 打开cmd,输入以下命令: npm install -g yarn检查是否安装成功&…