SQl注入小技巧

文章讲述了SQL注入的安全隐患,通过一个测试单元展示了如何利用字符串拼接导致的SQL注入问题。然后介绍了改进后的JdbcUtilPlus工具类,使用PreparedStatement进行参数化查询,以避免SQL注入,增强了代码安全性。示例中展示了新的查询方法,使用占位符替代字符串拼接,提高了代码的可读性和安全性。
摘要由CSDN通过智能技术生成

上篇文章中写的JdbcUtil工具类中关于sql部分会存在安全问题:
首先有t_user这样一张表:
在这里插入图片描述
表中只有aa和bb两个用户。

然后运行这个测试单元:

    @Test
    public void testLogin() {
        String username = "cc' or '1'='1";
        String password = "cc' or '1'='1";
        User user = selectRow("select * from t_users where username='" + username + "'and password='" + password+"'", User.class);
        System.out.println(user!=null?"登录成功":"登录失败");
    }

在这里插入图片描述
依然会显示用户登录成功,这是因为字符串拼接造成的问题,就叫sql注入。
可以使用以下JdbcUntilPlus代码:

    public static <T> List<T> list(String sql, Class<T> c,Object ... params) {
//        创建一个集合,存放所有对象
        List<T> tList = new ArrayList<>();
        try {
//        1.注册驱动-反射去加载jar包中com.mysql.jdbc.Drvier类的DriverManager.registerDriver(new Driver());
            Class.forName("com.mysql.jdbc.Driver");
//        2.获取连接对象
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/summer-camp2023?characterEncoding=utf-8", "root", "1234");
//        4.需要创建statement执行sql
            PreparedStatement statement = con.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                statement.setObject(i+1,params[i]);
            }
//        5.statement执行sql,返回结果集
            ResultSet rs = statement.executeQuery();
//            结果集rs得到结果集元数据
            ResultSetMetaData md = rs.getMetaData();
//            获取结果集的总列数
            int columnCount = md.getColumnCount();
//        6.解析rs
            while (rs.next()) {//光标向下移动一行,光标默认在列名那一行
//                根据每一行数据,封装成一个实体对象
                T t = c.newInstance();

//               1.取出某一行的每个数据,封装到对象t的属性中
                for (int i = 1; i < columnCount + 1; i++) {
//                    通过列的序号获取每一列的值
                    Object value = rs.getObject(i);
                    if (value != null) {
//                    通过列的序号获取每一列的列名
                        String columnName = md.getColumnName(i);
//                    因为列名和实体类t中的属性名一致,为每一个属性构造一个反射中的set方法
                        Field f = c.getDeclaredField(columnName);
//                        赋予私有属性的赋值权限
                        f.setAccessible(true);
//                    使用反射,把value给到对象t的属性中
                        f.set(t, value);//理解为:把value赋值给对象t的columnName属性,相对于set方法
                    }
                }
//                把对象存入集合中
                tList.add(t);
            }
//        7.关闭资源
            statement.close();
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tList;
    }

首先使用了可变长参数params,然后在其中的sql代码部分,使用了Statement的子类PreparedStatement来提前接收sql语句,随后根据params数组的长度使用for循环分别设置指定参数的值,使用了这个方法后再调用selectRow时就可以像下面这样使用?占位符:

User user = selectRow("select * from t_users where username= ? and password= ? ", User.class,username,password);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值