欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-31 10:22:28
本人微信公众号,欢迎扫码关注! 使用jdbc拼接条件查询语句时如何防止sql注入 最近公司的项目在上线时需要进行安全扫描,但是有几个项目中含有部分老代码,操作数据库时使用的是jdbc,并且竟然好多都是拼接的SQL语句,真是令人抓狂。 在具体改造时,必须使用PreparedStatement来防止SQ ......

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

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

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

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

    1 数据库示例数据

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

    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注入带来的风险。