sql注入原理防御sql注入原因以及预防方案sql注入原理及防范




sql注入原理防御sql注入原因以及预防方案sql注入原理及防范

2022-07-21 2:24:55 网络知识 官方管理员

前沿

在现有的框架中sql防注入已经做得很好了,我们需要做的就是尽量不要使用sql拼接调用

javasql注入原因以及预防方案(易理解)

1.SQL注入

1.1原理

SQL注入是通过客户端的输入把SQL命令注入到一个应用的数据库中,从而执行恶意的SQL语句

1.2演示

1.2.1案例1

有一个登录框,需要输入用户名和密码,然后我们的密码输入'or'123'='123这样的。我们在查询用户名和密码是否正确的时候,本来执行的sql语句是:select*fromuserwhereusername=''andpassword=''.这样的sql语句,现在我们输入密码是如上这样的,然后我们会通过参数进行拼接,拼接后的sql语句就是:

select*fromuserwhereusername=''andpassword=''or'123'='123';这样的了,那么会有一个or语句,只要这两个有一个是正确的话,就条件成立,因此123=123是成立的。因此验证就会被跳过。这只是一个简单的例子,

1.2.2案例2

密码比如是这样的:';droptableuser;,这样的话,那么sql命令就变成了:

select*fromuserwhereusername=''andpassword='';droptableuser;',那么这个时候我们会把user表直接删除了。

1.3防范

1.3.1前端

  • 前端表单进行参数格式控制;

1.3.2后端

  • 我们可以使用预编译语句(PreparedStatement,这样的话即使我们使用sql语句伪造成参数,到了服务端的时候,这个伪造sql语句的参数也只是简单的字符,并不能起到攻击的作用。
  • 使用正则表达式过滤传入的参数

注意:永远也不要把未经检查的用户输入的值直接传给数据库

  • java中的验证字符串是否包含sql的判断
packagecn.javanode.thread;importjava.util.regex.Pattern;/***@authorxgt(小光头)*@version1.0*@date2021-1-811:48*/publicclassCheckSqlDemo{/**正则表达式**/privatestaticStringreg="(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"+"(\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";privatestaticPatternsqlPattern=Pattern.compile(reg,Pattern.CASE_INSENSITIVE);privatestaticbooleanisValid(Stringstr){if(sqlPattern.matcher(str).find()){System.out.println("未能通过过滤器:str="+str);returnfalse;}returntrue;}publicstaticvoidmain(String[]args){System.out.println(isValid("tongji_user_add"));}}

补充

PreparedStatement是如何防止SQL注入的?

1.拼接参数(sql注入)

Connectionconnection=DriverManager.getConnection(DB_URL,USER,PASS);PreparedStatementpreparedStatement=connection.prepareStatement(sql);Stringparam="'test'or1=1";Stringsql="selectfilefromfilewherename="+param;//拼接SQL参数ResultSetresultSet=preparedStatement.executeQuery();System.out.println(resultSet.next());

输出结果为true,DB中执行的SQL为

--永真条件1=1成为了查询条件的一部分,可以返回所有数据,造成了SQL注入问题selectfilefromfilewherename='test'or1=1

2.setString(防注入)

Connectionconnection=DriverManager.getConnection(DB_URL,USER,PASS);PreparedStatementpreparedStatement=connection.prepareStatement(sql);preparedStatement.setString(1,account);//设置参数preparedStatement.setString(2,password);ResultSetresultSet=preparedStatement.executeQuery();//执行查询sql,获取结果集

输出结果为false,DB中执行的SQL为

selectfilefromfilewherename='\'test\'or1=1'

我们可以看到输出的SQL是把整个参数用引号包起来,并把参数中的引号作为转义字符,从而避免了参数也作为条件的一部分

3.源码分析

结论

  • preparedStatement.setString会判断当前参数的符号是否需要转义,是的话加的转义符
  • 如果不需要,则直接加上引号

sql注入原理防御(sql注入原因以及预防方案)(1)

//完整代码publicvoidsetString(intparameterIndex,Stringx)throwsSQLException{synchronized(checkClosed().getConnectionMutex()){//ifthepassedstringisnull,thensetthiscolumntonullif(x==null){setNull(parameterIndex,Types.CHAR);}else{checkClosed();intstringLength=x.length();if(this.connection.isNoBackslashEscapesSet()){//Scanforanynastychars//判断是否需要转义booleanneedsHexEscape=isEscapeNeededForString(x,stringLength);if(!needsHexEscape){byte[]parameterAsBytes=null;StringBuilderquotedString=newStringBuilder(x.length()+2);quotedString.append('\'');quotedString.append(x);quotedString.append('\'');if(!this.isLoadDataQuery){parameterAsBytes=StringUtils.getBytes(quotedString.toString(),this.charConverter,this.charEncoding,this.connection.getServerCharset(),this.connection.parserKnowsUnicode(),getExceptionInterceptor());}else{//SendwithplatformcharacterencodingparameterAsBytes=StringUtils.getBytes(quotedString.toString());}setInternal(parameterIndex,parameterAsBytes);}else{byte[]parameterAsBytes=null;if(!this.isLoadDataQuery){parameterAsBytes=StringUtils.getBytes(x,this.charConverter,this.charEncoding,this.connection.getServerCharset(),this.connection.parserKnowsUnicode(),getExceptionInterceptor());}else{//SendwithplatformcharacterencodingparameterAsBytes=StringUtils.getBytes(x);}setBytes(parameterIndex,parameterAsBytes);}return;}

发表评论:

最近发表
网站分类
标签列表