sql注入及用PrepareStatement就不用担心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.cn/138874.html原文链接:https://javaforall.cn
相关文章
- 从SSTI模板注入到内存马
- 实战 | 简单的sql注入与脚本的编写
- @Configuration 相关依赖注入问题
- 【愚公系列】2023年03月 Java教学课程 112-JDBC的(SQL注入和事务)
- SQL开发知识:sql注入过程详解
- 什么是javascript注入攻击详解编程语言
- Oracle中使用SQL删除字段(oracle删除字段sql)
- 环境预防SQL注入, 把Oracle环境保护好(sql注入oracle)
- SQL Server数据库:防范SQL注入(sqlserver注入)
- 漏洞预警:Zabbix高危SQL注入漏洞,可获取系统权限
- Oracle新增SQL方法详解(oracle新增sql)
- MySQL如何有效防止SQL注入攻击?(mysql防sql注入)
- Oracle表空间管理:精通SQL(oracle表空间sql)
- 安全提升:如何有效防范Oracle注入工具(oracle注入工具)
- 如何优化SQL访问Oracle数据库?(sql访问oracle)
- serverOracle 与 SQL Server之间的友谊连接(oracle连接sql)
- SQL注入攻击对MSSQL的威胁及防护策略(sql注入 mssql)
- 数据库利用SQL文件建立MSSQL数据库的步骤(sql文件建立mssql)
- 深入了解MySQL事务SQL的特性和用法(mysql事务sql)
- 探索Oracle的SQL跟踪工具:优化数据库性能的重要利器(oracle跟踪sql工具)
- Oracle通过SQL脚本实现快速操作(oracle执行sql脚本)
- MySQL数据库的SQL导入方法简介(sql导入mysql数据库)
- MySQL中防御SQL注入攻击的方法(mysql中sql注入)
- C语言注入MySQL的秘诀(C入mysql)
- sql使用cxoracle写出优化的SQL(cx_oracle写死)
- SQL与Redis实现数据的迅速存取(sql与redis)
- MySQL查询父子级关系的SQL语句(mysql 上下级sql)
- Oracle数据库如何防范SQL注入(oracle会sql注入)
- Oracle和SQL调试精准定位问题所在(oracle、sql调试)
- 认真学习,精通 Oracle SQL 编写技巧(oracle sql编写)
- PHP与SQL注入攻击[二]
- 在Global.asax文件里实现通用防SQL注入漏洞程序(适应于post/get请求)