• 使用jdbc拼接条件查询语句时如何防止sql注入


    本人微信公众号,欢迎扫码关注!

    使用jdbc拼接条件查询语句时如何防止sql注入

    • 最近公司的项目在上线时需要进行安全扫描,但是有几个项目中含有部分老代码,操作数据库时使用的是jdbc,并且竟然好多都是拼接的SQL语句,真是令人抓狂。
    • 在具体改造时,必须使用PreparedStatement来防止SQL注入,普通SQL语句比较容易改造,本重点探讨在拼接查询条件的时候如何方式SQL注入,具体思路请参考下面的示例代码。

    1 数据库示例数据

    2 使用statement(不防止SQL注入)

    2.1 示例代码

    @Test
    public void statementTest() {
        String username = "tom";
        String sex = "1";
        String address = "' or '1'='1";
        Statement stat = null;
        ResultSet res = null;
    
        Connection conn = ConnectionFactory.getConnection();
        String sql = "SELECT * FROM user WHERE 1 = 1";
    
        sql += username == null ? "" : " AND username = '" + username + "'";
        sql += sex == null ? "" : " AND sex = '" + sex + "'";
        sql += address == null ? "" : " AND address = '" + address + "'";
    
        System.out.println(sql);
    
        try {
            stat = conn.createStatement();
            res = stat.executeQuery(sql);
            printRes(res);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            ResourceClose.close(res, stat, conn);
        }
    }
    

    2.2 控制台结果

    SELECT * FROM user WHERE 1 = 1 AND username = 'tom' AND sex = '1' AND address = '' or '1'='1'
    10 tom 2014-07-10 1 beijing 
    16 tom 2018-07-31 1 shanghai 
    22 tom 2019-04-16 2 shanghai 
    24 tom 2019-06-22 1 guangzhou 
    25 tom 2019-01-22 2 guangzhou 
    28 tom 2018-07-31 1 shenzhen 
    

    2.3 小结

    • 经过上面的示例代码我们可以发现,单纯拼接SQL语句是非常危险的,特别容易被SQL注入,但是如果使用prepareStatement的话,像这种条件查询我们预先并不能确定到底有多少个?(占位符),也就不能使用按照?(占位符)索引去设置参数了,那怎么办呢?
    • 别担心,此时我们使用一个小小的技巧,具体参考下面的示例代码

    3 使用prepareStatement(可以防止SQL注入)

    3.1 示例代码

    @Test
    public void prepareStatementTest() {
        String username = "tom";
        String sex = null;
        String address = "' or '1'='1";
        PreparedStatement stat = null;
        ResultSet res = null;
    
        Connection conn = ConnectionFactory.getConnection();
        String sql = "SELECT * FROM user WHERE 1 = 1";
    
        List<Object> param = new ArrayList<>();
    
        if (username != null) {
            sql += " AND username = ?";
            param.add(username);
        }
        if (sex != null) {
            sql += " AND sex = ?";
            param.add(sex);
        }
        if (address != null) {
            sql += " AND address = ?";
            param.add(address);
        }
        System.out.println(sql);
    
        try {
            stat = conn.prepareStatement(sql);
            for (int i = 0; i < param.size(); i++) {
                stat.setObject(i+1,param.get(i));
            }
            res = stat.executeQuery();
            printRes(res);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            ResourceClose.close(res, stat, conn);
        }
    }
    

    3.2 控制台结果

    SELECT * FROM user WHERE 1 = 1 AND username = ? AND address = ?
    

    3.3 小结

    • 可以看出,使用prepareStatement是可以防止SQL注入的。
    • 但进行类似条件拼接这种操作时,可以先把参数放入一个集合中,然后遍历集合,同时利用setObject(index,obj)这个方法就可以动态的获取参数的索引了,而且不用关心参数是何种类型。

    4 问题总结

    • 如今在进行项目开发时已经很少使用原生的jdbc了,大多数都用功能强大的框架去完成,他们帮我们简化了很多操作,如获取数据库连接、封装结果集、SQL预编译(可以防止SQL注入)
    • 如果实在避免不了使用的话一定要使用可以需编译的prepareStatement对象,避免被SQL注入带来的风险。
  • 相关阅读:
    复旦大学软件学院预推免经验贴
    寒武纪-算法研究实习生

    C++ 笔记
    Deep Layer Aggregation论文笔记
    项目:语义分割DeepLabv3-树莓派4B部署
    神经网络加速引擎对比调研
    东南大学网安学院预推免经验帖
    中科院深圳先进院夏令营经验贴
    华东师范大学软院夏令营经验贴
  • 原文地址:https://www.cnblogs.com/intflag/p/10780577.html
Copyright © 2020-2023  润新知