用java PreparedStatement就不用担心sql注入了吗

 我来答
ifeilong
2016-09-10 · TA获得超过8068个赞
知道大有可为答主
回答量:1187
采纳率:100%
帮助的人:785万
展开全部

对java有了解的同学基本上都体验过JDBC,基本都了解PreparedStatement,PreparedStatement相比Statement基本解决了SQL注入问题,而且效率也有一定提升。


     关于PreparedStatement和Statement其他细节我们不讨论,只关心注入问题。无论读者是老鸟还是菜鸟,都需要问一下自己,PreparedStatement真的百分百防注入吗?


     接下来我们研究一下PreparedStatement如何防止注入,本文以MySQL数据库为例。


     为了避免篇幅过长,我这里只贴代码片段,希望读者能有一定的基础。

String sql = "select * from goods where min_name = ?";  // 含有参数
PreparedStatement st = conn.prepareStatement(sql);
st.setString(1, "儿童"); // 参数赋值
System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@d704f0: select * from goods where min_name = '儿童'


     这段代码属于JDBC常识了,就是简单的根据参数查询,看不出什么端倪,但假如有人使坏,想注入一下呢?

String sql = "select * from goods where min_name = ?";  // 含有参数
PreparedStatement st = conn.prepareStatement(sql);
st.setString(1, "儿童'"); // 参数赋值
System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@d704f0: select * from goods where min_name = '儿童\''

     简单的在参数后边加一个单引号,就可以快速判断是否可以进行SQL注入,这个百试百灵,如果有漏洞的话,一般会报错。


     之所以PreparedStatement能防止注入,是因为它把单引号转义了,变成了\',这样一来,就无法截断SQL语句,进而无法拼接SQL语句,基本上没有办法注入了。


     所以,如果不用PreparedStatement,又想防止注入,最简单粗暴的办法就是过滤单引号,过滤之后,单纯从SQL的角度,无法进行任何注入。


     其实,刚刚我们提到的是String参数类型的注入,大多数注入,还是发生在数值类型上,幸运的是PreparedStatement为我们提供了st.setInt(1, 999);这种数值参数赋值API,基本就避免了注入,因为如果用户输入的不是数值类型,类型转换的时候就报错了。


     好,现在读者已经了解PreparedStatement会对参数做转义,接下来再看个例子。

String sql = "select * from goods where min_name = ?";  // 含有参数
PreparedStatement st = conn.prepareStatement(sql);
st.setString(1, "儿童%"); // 参数赋值
System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@8543aa: select * from goods where min_name = '儿童%'


     我们尝试输入了一个百分号,发现PreparedStatement竟然没有转义,百分号恰好是like查询的通配符。

     正常情况下,like查询是这么写的:

String sql = "select * from goods where min_name like ?";  // 含有参数
st = conn.prepareStatement(sql);
st.setString(1, "儿童" + "%"); // 参数赋值
System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@8543aa: select * from goods where min_name like '儿童%'

     查询min_name字段以"儿童"开头的所有记录,其中"儿童"二字是用户输入的查询条件,百分号是我们自己加的,怎么可能让用户输入百分号嘛!等等!如果用户非常聪明,偏要输入百分号呢?

String sql = "select * from goods where min_name like ?";  // 含有参数
st = conn.prepareStatement(sql);
st.setString(1, "%儿童%" + "%"); // 参数赋值
System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@8543aa: select * from goods where min_name like '%儿童%%'

     聪明的用户直接输入了"%儿童%",整个查询的意思就变了,变成包含查询。实际上不用这么麻烦,用户什么都不输入,或者只输入一个%,都可以改变原意。

     虽然此种SQL注入危害不大,但这种查询会耗尽系统资源,从而演化成拒绝服务攻击。


     那如何防范呢?笔者能想到的方案如下:

        

          ·直接拼接SQL语句,然后自己实现所有的转义操作。这种方法比较麻烦,而且很可能没有PreparedStatement做的好,造成其他更大的漏洞,不推荐。

          ·直接简单暴力的过滤掉%。笔者觉得这方案不错,如果没有严格的限制,随便用户怎么输入,既然有限制了,就干脆严格一些,干脆不让用户搜索%,推荐。  

千锋教育
2018-07-29 · 做真实的自己 用良心做教育
千锋教育
千锋教育专注HTML5大前端、JavaEE、Python、人工智能、UI&UE、云计算、全栈软件测试、大数据、物联网+嵌入式、Unity游戏开发、网络安全、互联网营销、Go语言等培训教育。
向TA提问
展开全部
SQL Injection:是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令
select * from tab_name where name= '"+name+"' and passwd='"+passwd+"';
把其中passwd换成 [' or '1' = '1] 这样就可以完成sql注入
PreparedStatement 对象用于执行带或不带参数的预编译 SQL 语句
PreparedStatement 不允许在不同的插入时间改变查询的逻辑结构,所以这种注入方式无效
本回答被网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
匿名用户
2016-09-10
展开全部
一般的情况,不用担心的了。。。。。。。。。。。。。。。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 1条折叠回答
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式