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

JDBC模拟SQL注入和避免SQL注入

请添加图片描述

模拟用户登录
用户名:fdsa
密码:fdsa’ or ‘1’='1
select * from t_user where login_name=‘fdsa’ and login_pwd=‘fdsa’ or ‘1’='1’登录成功。以上随意输入一个用户名和密码,登录成功了,这种现象被称为SQL注入现象!

导致SOL注人的根本原因是什么?怎么解决?
导致SOL注入的根本原因是:用户不是一般的用户,用户是懂得程序的,输入的用户名信息以及密码信息中含有SOL语句的关健字,这个SQL语句的关健字和底层的SQL语句进行 “字符串拼接”,导致原SQL语句的含义被扭曲了。最最最最最最主要的原因是:用户提供的信息参与了SQL语句的编译。

主要因素是:这个程序是先进行的字符串拼接,然后再进行的SQL语句的编译,正好被注入。

模拟SQL注入代码实战


public class 模拟SQL注入 {
    public static void main(String[] args) {
        //初始化一个界面,可以让用户输入用户名和密码
        Map<String, String> map = initUI();

        //连接数据库验证用户名和密码是否正确
        boolean ok = checkNameAndPwd(map.get("a"),map.get("b"));
        System.out.println(ok ? "登陆成功" : "登录失败");
    }

    /**
     * 验证用户名和密码
     * @param a 登录名
     * @param b 登录密码
     * @return true表示登陆成功  false表示登录失败
     */
    private static boolean checkNameAndPwd(String a, String b) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        boolean ok = false; //默认登录失败的

        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/feifei","root","297744");
            //3.获取数据库操作对象
            stmt = conn.createStatement();
            //4.执行SQL语句
            String sql = "select * from aa where name='"+ a +"' and mima = '"+b+"'";
            System.out.println(sql);
            rs = stmt.executeQuery(sql);//程序执行到此处,才会将sql语句发送到DBMS上,DBMS进行SQL语句编译
            //处理查询结果集
            //如果以上sql语句中用户和密码是正确的,那么结果集最多也就查询出一条记录,所以不需要while
            if (rs.next()){
                ok = true;
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return ok;
    }

    /**
     * 初始化界面,并接收用户的输入
     * @return 存储登录和登录密码的Map集合
     */
    private static Map<String,String> initUI() {
        System.out.println("欢迎使用系统,请输入用户名和密码进行身份确认");
        Scanner sc = new Scanner(System.in);
        System.out.println("用户名:");
        String  a = sc.next();
        System.out.println("密码:");
        String  b = sc.next();
        //将用户名和密码放到map集合中
        Map map = new HashMap();
        map.put("a",a);
        map.put("b",b);
        //返回Map
        return map;
    }


}

那么可以看到,通过SQL注入的方法就可以实现登录,==那么我们应该怎么避免注入呢?==SQL注入的根本原因是:先进行了字符串的拼接,然后再进行的编译

java.sql.statement接口的特点:先进行字符串的拼接,然后再进行sql语句的编译。
优点:使用statement可以进行sql语句的拼接。
缺点:因为拼接的存在,导致可能给不法分子机会。导致SQL注入。

java.sql.PreparedStatement接口的特点:先进行SQL语句的编译,然后再进行sql语句的传值。
优点:避免SQL注入。
缺点:没有办法进行sql语句的拼接,只能给sql语句传值。
PreparedStatement预编译的数据库操作对象。

代码实战使用PreparedStatement解决sql注入。

public class 解决SQL注入问题 {
    public static void main(String[] args) {
        //初始化一个界面,可以让用户输入用户名和密码
        Map<String, String> map = initUI();

        //连接数据库验证用户名和密码是否正确
        boolean ok = checkNameAndPwd(map.get("a"),map.get("b"));
        System.out.println(ok ? "登陆成功" : "登录失败");
    }

    /**
     * 验证用户名和密码
     * @param a 登录名
     * @param b 登录密码
     * @return true表示登陆成功  false表示登录失败
     */
    private static boolean checkNameAndPwd(String a, String b) {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        boolean ok = false; //默认登录失败的

        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/feifei","root","297744");

            //3.获取预编译的数据库操作对象
            //注意:一个问号?是一个占位符,一个占位符只能接受一个值/数据。占位符不能用单引号括起来
            String sql = "select * from aa where name= ? and mima = ?";
            stmt = conn.prepareStatement(sql);//此时发生sql给DBMS 进行sql语句的编译
            //给占位符?传值
            //jdbc中所有下标都是从1开始
            //怎么解决SQL注入的:即使用户信息中有sql关键字,但是不参加编译就没事。
            //stmt.setInt(1,444); 如果是setIng的话里面就要传入一个数字.setString是字符串
            stmt.setString(1,a);//1代表第一个?
            stmt.setString(2,b);//2代表第二个?

            //4.执行SQL语句
            //这个方法不能将SQL语句传进去,不能是这样rs = stmt.executeQuery(sql);
            rs = stmt.executeQuery();

            //5处理查询结果集
            //如果以上sql语句中用户和密码是正确的,那么结果集最多也就查询出一条记录,所以不需要while
            if (rs.next()){
                ok = true;
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }
        return ok;
    }

    /**
     * 初始化界面,并接收用户的输入
     * @return 存储登录和登录密码的Map集合
     */
    private static Map<String,String> initUI() {
        System.out.println("欢迎使用系统,请输入用户名和密码进行身份确认");
        Scanner sc = new Scanner(System.in);
        System.out.println("用户名:");
        String  a = sc.next();
        System.out.println("密码:");
        String  b = sc.next();
        //将用户名和密码放到map集合中
        Map map = new HashMap();
        map.put("a",a);
        map.put("b",b);
        //返回Map
        return map;
    }
}

相关文章:

  • flink在企业IT架构中如何定位-在选型流批一体技术与大数据架构时的避坑指南
  • JUC并发编程之CompletableFuture基础用法
  • SpringBoot+Mybatis-Plus多数据源使用
  • Colab-免费GPU算力
  • 【CH559L单片机】串口下载程序说明
  • CMake中macro的使用
  • windows利用msys2安装minGW64
  • (42)STM32——LCD显示屏实验笔记
  • 全国青少年软件编程等级考试标准Python(1-6级)
  • Java语法基本概念
  • 一文搞懂CSS盒子模型
  • 【PAT甲级】1123 Is It a Complete AVL Tree
  • PWM实验(控制蜂鸣器,风扇,马达)
  • MySQL 从入门到入狱 rm - rf /* 咳咳~ 到精通
  • 回溯算法 - 二叉树中和为某一值的路径 字符串的排列
  • “大数据应用场景”之隔壁老王(连载四)
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Angular 4.x 动态创建组件
  • Debian下无root权限使用Python访问Oracle
  • docker容器内的网络抓包
  • Javascript基础之Array数组API
  • Markdown 语法简单说明
  • Mysql5.6主从复制
  • python 学习笔记 - Queue Pipes,进程间通讯
  • Vue.js 移动端适配之 vw 解决方案
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 扑朔迷离的属性和特性【彻底弄清】
  • 前端技术周刊 2019-01-14:客户端存储
  • 如何在 Tornado 中实现 Middleware
  • 收藏好这篇,别再只说“数据劫持”了
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • $ git push -u origin master 推送到远程库出错
  • ( 10 )MySQL中的外键
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (Note)C++中的继承方式
  • (Oracle)SQL优化技巧(一):分页查询
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (十) 初识 Docker file
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • .net 4.0发布后不能正常显示图片问题
  • .net CHARTING图表控件下载地址
  • .net core 6 redis操作类
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .net和jar包windows服务部署
  • .NET框架
  • @DateTimeFormat 和 @JsonFormat 注解详解
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • @Valid和@NotNull字段校验使用
  • [.net] 如何在mail的加入正文显示图片
  • [.net]官方水晶报表的使用以演示下载