sql注入及用PrepareStatement就不用担心sql注入了吗?

sql注入及用PrepareStatement就不用担心sql注入了吗?首先讲一下sql注入所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露

大家好,又见面了,我是你们的朋友全栈君。

首先讲一下sql注入

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到sql注入攻击。
验证绕过漏洞就是’or’=’or’后台绕过漏洞,利用的就是AND和OR的运算规则,从而造成后台脚本逻辑性错误。
先举个例子,你要登录一个网站,上面让你输入用户名字和密码。那么,假如你输入的用户名是 admin ,但是你不知道密码,你就输入了一个 1′ OR ‘1’ = ‘1 ,那么,你就提交了两个参数给服务器。假如,服务器拿这两个参数拼SQL语句:SELECT T.* FROM XXX_TABLE TWHERE T.USER_ID = ‘/*param1*/’AND T.PASSWORD = ‘/*param2*/’那么,你提交的两个参数就使SQL文变成了:SELECT T.* FROM XXX_TABLE TWHERE T.USER_ID = ‘admin’AND T.PASSWORD = ‘1’ OR ‘1’ = ‘1’那么,这个SQL原来的校验功能就被你绕过去了,你的这种行为就称之为SQL注入。

接下来用PrepareStatement就不用担心sql注入了吗?

下面内容转载自https://www.cnblogs.com/iyangyuan/archive/2015/09/15/4809494.html
 言归正传,对java有了解的同学基本上都体验过JDBC,基本都了解PreparedStatement,PreparedStatement相比Statement基本解决了SQL注入问题,而且效率也有一定提升。
     关于PreparedStatement和Statement其他细节我们不讨论,只关心注入问题。无论读者是老鸟还是菜鸟,都需要问一下自己,PreparedStatement真的百分百防注入吗?
     接下来我们研究一下PreparedStatement如何防止注入,本文以MySQL数据库为例。
     为了避免篇幅过长,我这里只贴代码片段,希望读者能有一定的基础。
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 = ?"; // 含有参数 PreparedStatement st = conn.prepareStatement(sql); st.setString(1, "儿童%"); // 参数赋值 System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@8543aa: select * from goods where min_name = '儿童%'


  查询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做的好,造成其他更大的漏洞,不推荐。
          ·直接简单暴力的过滤掉%。笔者觉得这方案不错,如果没有严格的限制,随便用户怎么输入,既然有限制了,就干脆严格一些,干脆不让用户搜索%,推荐。
        
     目前做搜索,只要不是太差的公司,一般都有自己的搜索引擎(例如著名的java开源搜索引擎solr),很少有在数据库中直接like的,笔者并不是想在like上钻牛角尖,而是提醒读者善于思考,每天都在写着重复的代码,却从来没有停下脚步细细品味。
     有读者可能会问,为什么我们不能手动转义一下用户输入的%,其他的再交给PreparedStatement转义?这个留作思考题,动手试一下就知道为什么了。
     注意,JDBC只是java定义的规范,可以理解成接口,每种数据库必须有自己的实现,实现之后一般叫做数据库驱动,本文所涉及的PreparedStatement,是由MySQL实现的,并不是JDK实现的默认行为,也就是说,不同的数据库表现不同,不能一概而论。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/138874.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharm2018打不开_pycharm indexing

    pycharm2018打不开_pycharm indexingpycharm2020无法打开,点击无反应,今天我碰到这现象,总结大体原因为2种第1种:C:\Users\ygw\AppData\Roaming\JetBrains(删除该目录即可,一般由于升级安装或安装两个不同版本会存在老旧文件影响导致)第2种:进行过激活成功教程,修改了pycharm64.exe.vmoptions配置,其中存在错误配置或配置中的指定jar…

    2022年8月29日
    0
  • mac. idea2021.5 激活码(最新序列号破解)

    mac. idea2021.5 激活码(最新序列号破解),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
    47
  • 树莓派 网络设置_树莓派4b教程

    树莓派 网络设置_树莓派4b教程概览你想做的第一件事一定是把你的树莓派连接到因特网上。在这节课里,你将会学到如何:使用网线连接到以太网在Raspbian和Occidentalis上使用无线网卡找到树莓派的IP地址使用有线网络最快的把树莓派接入到因特网的方法是使用一根以太网线把树莓派连接到你家的路由器上。当你把网线连入树莓派的时候,你就会看到网络LED灯开始闪烁了。对于大多数的家庭网络来说,你就不需要再做任何进一步的配置了。但为了…

    2022年9月13日
    0
  • 【蓝牙sbc协议】sbc源码阅读笔记(四)——sbc_encode函数详解

    【蓝牙sbc协议】sbc源码阅读笔记(四)——sbc_encode函数详解sbc_encode函数详解函数定义://sbc.cSBC_EXPORTssize_tsbc_encode(sbc_t*sbc,constvoid*input,size_tinput_len, void*output,size_toutput_len,ssize_t*written){ structsbc_priv*priv; intsamples; ssize_tframelen; int(*sbc_enc_process_input)(int

    2022年9月11日
    0
  • webstorm激活码最新2021【2021最新】

    (webstorm激活码最新2021)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月22日
    105
  • qtum量子链官网_币宽BitQuant量化交易系统

    qtum量子链官网_币宽BitQuant量化交易系统全球专业交易所Bithumb Global上线Qtum量子链,开启QTUM交易大赛

    2022年4月22日
    77

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号