文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一文搞懂Java JDBC中的SQL注入问题

2022-11-13 18:58

关注

?SQL注入

✨什么是SQL注入

在用户输入的数据中有SQL关键字或语法,并且关键字或语法参与了SQL语句的编译。导致SQL语句编译后的条件为true,一直得到正确的结果。这种现象就是SQL注入

✨SQL注入的效果的演示

?SQL注入代码

package cn.bdqn.demo03;
​
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
​
public class Login {
​
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        
        //创建Scanner类对象,从控制台获取用户名和密码数据
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String user = sc.nextLine();//使用nextLine()方法获取字符串
        System.out.println("请输入密码:");
        String pwd = sc.nextLine();//使用nextLine()方法获取字符串
        
        //1、注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2、获取连接对象
        String url = "jdbc:mysql://127.0.0.1:3306/java221804";
        String dbuser = "root";
        String pssword = "123456";
        Connection connection = DriverManager.getConnection(url, dbuser, pssword);
        //3、获取发送SQL语句的对象
        Statement statement =connection.createStatement();
        //编写SQL语句
        String sql = "SELECT * FROM user WHERE username='"+user+"' AND pssword = '"+pwd+"';";
        //4、执行SQL语句
        ResultSet resultSet=statement.executeQuery(sql);
        if(resultSet.next()){
            System.out.println("用户名和密码正确,登录成功");
        }else{
            System.out.println("用户名或密码不正确,登录失败");
        }
        //6、关闭资源
        resultSet.close();
        statement.close();
        connection.close();
        sc.close();
    }
}

?SQL注入效果

输入错误的用户名和密码,提示登录失败:

输入错误的用户名和密码,提示登录成功:产生了SQL注入

上面案例代码中,当你的用户名为 abc' or 1=1;# 密码为123,拼接到SQL语句中,变成如下效果:

SELECT * FROM user WHERE username='abc' or 1=1;#' AND pssword = '123';

此SQL语句or 后面1=1永远正确,#后面的成了注释,所以这条语句会将表中所有的数据查询出来,然后再做数据判断的时候,就会得到正确结果,从而说用户名和密码正确,登录成功。

✨如何避免SQL注入

使用PreparedStatement代替Statement可以有效防止SQL注入的发生。由于SQL注入产生的原因是在用户输入数据对SQL整合,整合后再发送到数据库进行编译产生的。

所以为了避免SQL注入,就需要SQL语句在用户输入数据前就进行编译,成为完整的SQL语句,编译完成后再进行数据填充。这个操作需要使用PrepareStatement实现。

PreparedStatement利用预编译的机制将sql语句的主干和参数分别传输给数据库服务器,从而使数据库分辨的出哪些是sql语句的主干哪些是参数,这样一来即使参数中带了sql的关键字,数据库服务器也仅仅将他当作参数值使用,关键字不会起作用,从而从原理上防止了sql注入的问题。

?PrepareStatement解决SQL注入

PreparedStatement接口继承了Statement接口,执行SQL语句的方法与Statement执行SQL语句的方法相同。

✨PreparedStatement的应用

PreparedStatement的作用:

?参数标记

//预编译SQL语句,SQL中的所有参数由?符号占位,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。

String sql = "select * from user where userName = ? and pssword=?;";

PreparedStatement preparedStatement = connection.prepareStatement(sql);

?动态参数绑定

preparedStatement.sexXxx(下标,值):参数下标从1开始,为指定参数下标绑定值。Xxx表示数据类型。

//绑定参数,有多少个?绑定多少个参数值

preparedStatement.setString(1, userName);

preparedStatement.setString(2, pwd);

✨综合案例

package cn.bdqn.demo02;
​
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
​
public class PreparedStatementDemo01 {
​
    public static void main(String[] args) throws ClassNotFoundException,SQLException {
​
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String userName = sc.nextLine();
        System.out.println("请输入密码:");
        String pwd = sc.nextLine();
​
        // 1、注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2、获得连接
        String url = "jdbc:mysql://localhost:3306/java2217";
        String user = "root";
        String pssword = "123456";
        Connection connection = DriverManager.getConnection(url, user, pssword);
        // 3、获取发送SQL对象
        String sql = "select * from user where userName = ? and pssword=?;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        // 4、绑定参数,有多少个?绑定多少个参数值
        preparedStatement.setString(1, userName);
        preparedStatement.setString(2, pwd);
        // 5、执行SQL语句,并处理结果
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {
            System.out.println("用户名和密码正确,登录成功");
        } else {
            System.out.println("用户名或密码错误,登录失败");
        }
        // 6、释放资源:与关闭流的方式一样,先开的后关,后开的先关
        resultSet.close();
        preparedStatement.close();
        connection.close();
        sc.close();
    }
}

✨PreparedStatement总结

PreparedStatement主要有如下的三个优点:

可以防止sql注入
由于使用了预编译机制,执行的效率要高于Statement
sql语句使用?形式替代参数,然后再用方法设置?的值,比起拼接字符串,代码更加优雅.

PreparedStatement 与Statment比较:

语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
效率不同: PreparedStatement可以使用sql缓存区,效率比Statment高
安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。

?必须使用Statement的情况

当sql语句中必须用到字符串拼接时,则必须使用Statement

public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        System.out.print("升序输入asc,降序输入desc:");
        String order = s.nextLine();
        // 定义变量
        Connection connection = null;
        Statement statement = null;
        ResultSet rs = null;
 
 
        try {
            // 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 获取连接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/MyTest","root", "********");
            // 获取数据库操作对象
            statement = connection.createStatement();
            // 执行sql
            String sql = "select * from emp order by sal " + order;
            rs = statement.executeQuery(sql);
            // 处理查询结果集
            while(rs.next()){
                String ename = rs.getString("ename");
                double sal = rs.getDouble("sal");
                System.out.println("姓名:" + ename + ",薪资:" + sal);
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

到此这篇关于一文搞懂Java JDBC中的SQL注入问题的文章就介绍到这了,更多相关jdbc sql 注入内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯