preparedstatement本质原理

SQL注入的预编译疑惑

前几天拜读绿盟大佬写的web应用安全编码时,看到有一页PPT上加了一句话备注,preparedstatement预编译本质也是过滤。就这一点问题我请教了一个老司机和阅读了相关资料后,觉得有必要写出来一下。

preparedstatement和statement

这两个对象字如其意,可以参考相关文档对他们的详细分析。preparedstatement就是我们常用的在JDBC中的预编译:

String sql="insert into account values(account_seq.nextval,?,?,?)";

pstm = conn.prepareStatement(sql, new String[]{"cardId"} );

pstm.setString(1, a.getName());

pstm.setString(2,a.getPassword());

pstm.setDouble(3,a.getBalance());

和现在常用开发框架SSM里的mybatis中的#预编译一样,对应statement就是mybatis里的$:

select id,username,password,age,sex from t_user_info where id=#{id}

预编译?

首先参考一下CSDN某大佬的博客,这个文章中简单扼要的说了https://blog.csdn.net/tang_2214/article/details/80349557:

其实简单想一下,这个理论就是经不起推敲的,使用参数化查询的情况下,数据库不会将参数的内容视为SQL执行的一部分,而是作为一个字段的属性值来处理。问题是如何将其作为一个字段的属性值?如果仅仅是加两个单引号包起来,那同样可以用单引号进行恶意SQL语句的溢出,因为语句的改变还是会导致重新编译,即使你预编译了一些固定语句。
比如上面的preparedstatmen场景显示应该还是有注入才对
String sql=“insert into account values(account_seq.nextval,?,?,?)”;
pstm = conn.prepareStatement(sql, new String[]{“cardId”} );
pstm.setString(1, “a’ or ‘1’='1”);

预编译本质是转义

查阅了相当多的资料之后,一篇真正的大佬文中做了解释,每个数据库处理预编译的形式不同,而mysql的jar源码包中提供了preparedstatement的实现https://blog.csdn.net/yan465942872/article/details/6753957

值得注意的是,此大佬对setstring方法的转义机制描述有些错误,正确的描述应该是在mysql中,是两边加单引号,参数中的单引号进行转义。而setint方法就是对字符型参数进行强制的类型转换来解决sql注入问题。

预编译之后还有可能有SQL注入吗?

答案是肯定的,看了上面推荐blog的setstring方法就知道,并未对%进行转义,至于为什么不去转义%,我是不知道,有兴趣的同学可以了解下。。。。。。

如果缺少了%号的转义,那就必须要考虑模糊查询like的问题,对于模糊查询的地方,比如某处固定username后的检索,都可以进行前置%的形式去绕过预编译。

OWASP提供的ESAPI中已经增加了对%的处理。

发布了5 篇原创文章 · 获赞 7 · 访问量 1823

猜你喜欢

转载自blog.csdn.net/silencediors/article/details/104085380