#{}如何防止SQL注入的?它的底层原理是什么?_sql

#{}如何防止SQL注入的?它的底层原理是什么?_sql System.out.println(user);     }
System.out.println(\”userList2: \”);
for (User user : userL

System.out.println(用户);

}

System.out.println(\’userList2:\’);

对于(用户user:userList2){

System.out.println(用户);

}

会话.关闭();

附寄();

}

显示执行结果。

![](https://img-blog.csdnimg.cn/img_convert/a3e258ee37b47eb45ab268c4f5342b5f.png)

查询您找到的所有内容

1.2 SQL注入问题

`${}` 会导致SQL 注入问题,但`#{}` 不会导致SQL 注入问题

我们来测试一下:

ListuserList2=userDao.findByUsername2(\’aaa\’or1=1\’);

System.out.println(\’userList2:\’);

对于(用户user:userList2){

System.out.println(用户);

}

查询生成的SQL语句:

![](https://img-blog.csdnimg.cn/img_convert/e9f09147797870985417d685cf2da327.png)

我传递的参数是aaa\’或1=1——并且查询了所有数据。

你能想象如果你想根据ID删除会发生什么吗?

deletefromuserwhereid=\’${value}\’

如果我通过的是:1\’或1=1——每个人都应该已经知道结果会是什么。

这里的ID是整数类型,所以无法测试。如果您有兴趣,请私下测试一下。

如果你使用上面的`#{}`,就不会有任何SQL注入问题。

![](https://img-blog.csdnimg.cn/img_convert/2ec3cde8bf0655ea5417855b0d439a37.png)

1.3 `${}` 和`#{}` 的区别

`#{}` 与JDBC 中的? 等价的占位符匹配。编译后,传递的值会添加双引号以防止SQL 注入问题。

`${}` 与传递的实际值匹配。一旦通过,SQL 语句和字符串就会组合在一起。由于${} 与其他SQL 字符串连接在一起,因此它不能防止SQL 注入问题。

显示`#{}`和`${}`生成的SQL语句。

![](https://img-blog.csdnimg.cn/img_convert/da2068fddd9856c931a520e151a25dbc.png)

Stringabc=“123”;

#{abc}=\”123\”

${值}=123;

1.4 `#{}`底层如何防止SQL注入?

1.4.1 网上的答案

网上关于此类问题的疑问很多,原因有两个。

**1)`#{}`底层使用的是预编译的PreparedStatement,所以不存在SQL注入问题。

其实预编译是MySQL本身的一个特性,与PreparedStatement无关。还有,预编译并不是我们理解的预编译,PreparedStatement底层默认是不使用预编译的(必须手动开启)。详情请参阅下文

**2) `${}` 会导致SQL 注入问题,因为`#{}` 不会产生字符串连接,但`${}` 会产生字符串连接。

这两个答案都经不起进一步的调查,最终的答案也只停留在表面,没有人知道其中的原因。

1.4.2 如何防止SQL注入?

让我们打开MySQL驱动程序源代码,看看会发生什么。

打开PreparedStatement类的setString()方法(MyBatis使用setString()方法向`#{}`传递参数,但不向`${}`传递参数)。

![](https://img-blog.csdnimg.cn/img_convert/a6c393020b2ed2e1cbc868d542eb978d.png)

setString()方法的所有源代码:

publicvoidsetString(intparameterIndex,Stringx)抛出SQLException{

同步(this.checkClosed()。getConnectionMutex()){

如果(x==null){

this.setNull(parameterIndex,1);

}除此之外{

this.checkClosed();

intstringLength=x.length();

字符串生成器缓冲区;

if(this.connection.isNoBackslashEscapesSet()){

booleanneedsHexEscape=this.isEscapeNeededForString(x,stringLength);

对象参数AsBytes;

byte[] 参数AsBytes;

if(!needsHexEscape){

参数AsBytes=null;

buf=newStringBuilder(x.length()+2);

buf.append(\’\’);

buf.append(x);

buf.append(\’\’);

if(!this.isLoadDataQuery){

参数AsBytes=StringUtils.getBytes(buf.toString(),this.charConverter,this.charEncoding,this.connection.getServerCharset(),this.connection.parserKnowsUnicode(),this.getExceptionInterceptor());

}除此之外{

参数AsBytes=StringUtils.getBytes(buf.toString());

}

this.setInternal(parameterIndex,parameterAsBytes);

}除此之外{

参数AsBytes=null;

if(!this.isLoadDataQuery){

parameterAsBytes=StringUtils.getBytes(x,this.charConverter,this.charEncoding,this.connection.getServerCharset(),this.connection.parserKnowsUnicode(),this.getExceptionInterceptor());

}除此之外{

参数AsBytes=StringUtils.getBytes(x);

}

this.setBytes(parameterIndex,parameterAsBytes);

}

返回;

}

字符串参数AsString=x;

booleanneedsQuoted=true;

if(this.isLoadDataQuery||this.isEscapeNeededForString(x,stringLength)){

需要引用=假;

buf=newStringBuilder((int)((double)x.length()*1.1D));

buf.append(\’\’);

for(inti=0;istringLength;++i){//遍历字符串得到每个字符

charc=x.charAt(i);

开关{

案例“\\u0000”:

buf.append(\’\\\’);

buf.append(\’0\’);

休息;

案例“\\n”:

buf.append(\’\\\’);

buf.append(\’n\’);

休息;

案例“\\r”:

buf.append(\’\\\’);

buf.append(\’r\’);

休息;

案例“\\u001a”:

buf.append(\’\\\’);

buf.append(\’Z\’);

休息;

案例\’\’:

if(this.usingAnsiMode){

buf.append(\’\\\’);

}

buf.append(\’\’\’\’);

休息;

案例\’\’:

buf.append(\’\\\’);

buf.append(\’\’);

休息;

案例“\\”:

buf.append(\’\\\’);

buf.append(\’\\\’);

休息;

案例“”:

外壳‘’:

if(this.charsetEncoder!=null){

CharBuffercbuf=CharBuffer.allocate(1);

ByteBufferbbuf=ByteBuffer.分配(1);

cbuf.put;

cbuf.position(0);

this.charsetEncoder.encode(cbuf,bbuf,true);

if(bbuf.get(0)==92){

buf.append(\’\\\’);

}

}

buf.append;

休息;

默认:

buf.append;

}

}

buf.append(\’\’);

参数AsString=buf.toString();

}

缓冲区=空;

byte[] 参数AsBytes;

if(!this.isLoadDataQuery){

if(需要引用){

parameterAsBytes=StringUtils.getBytesWrapped(parameterAsString,‘’’,‘’’,this.charConverter,this.charEncoding,this.connection.getServerCharset(),this.connection.parserKnowsUnicode(),this.getExceptionInterceptor());

}除此之外{

parameterAsBytes=StringUtils.getBytes(parameterAsString,this.charConverter,this.charEncoding,this.connection.getServerCharset(),this.connection.parserKnowsUnicode(),this.getExceptionInterceptor());

}

}除此之外{

参数AsBytes=StringUtils.getBytes(参数AsString);

}

this.setInternal(parameterIndex,parameterAsBytes);

this.parameterTypes[parameterIndex-1+this.getParameterIndexOffset()]=12;

}

}

}

执行`#{}`查询语句并观察断点。

![](https://img-blog.csdnimg.cn/img_convert/e8a97e476e1d5c4ba91f1984117ce301.png)

最终传递的参数为:

![](https://img-blog.csdnimg.cn/img_convert/e85268d0538b53b907cf84e642d4fc85.png)

最后传递的参数是:`\’aaa\\\’ or 1=1 –`

在数据库上运行以下SQL语句(无法查询到数据)。

select*fromuserwhereusernamelike\’aaa\’or1=1\’

![](https://img-blog.csdnimg.cn/img_convert/9692adb53a2af887dacb01a5629e6044.png)

如果我们删除添加到PreparedStatement 中的“/”会发生什么?让我们运行SQL。

select*fromuserwhereusernamelike\’aaa\’or1=1\’

![](https://img-blog.csdnimg.cn/img_convert/7355a91010d025251e46441377bad95a.png)

还可以通过MySQL日志观察`#{}`和`${}`生成的SQL语句来分析问题。

**1) 打开MySQL 日志记录:**

在MySQL配置文件的[mysqld]下添加以下配置:

#是否启用mysql日志0: off (默认值) 1: on

通用日志=1

哪个兄弟不知道你可以提前回答网络安全面试问题?我们整理了160多道网络安全面试题(金9银10),让你的网络安全面试脱颖而出,我花了一周的时间才完成。做吧。

工程师王兰一面试题及答案目前只对我哥有用。如果你能正确回答70% 的问题,那么你找到一份稳定的工作就不会有太大困难。

对于有1-3年工作经验后想换工作的朋友来说,这也是一个很好的资源!

【如何获取完整版在文末! ]

93 网络安全面试问题

我就不一一截图了,因为内容太多了。

黑客学习资源推荐

最后给大家分享一套完整的网络安全学习资料,对所有想学习网络安全的人都有用。

对于刚接触网络安全的学生,我们创建了详细的学习和成长路线图。这可以说是最科学、最系统的学习路线。每个人都可以遵循这个大方向。

朋友们,如果您需要的话,请联系我们获取~

1零基础入门

学习路线

对于刚接触网络安全的学生,我们创建了详细的学习和成长路线图。这可以说是最科学、最系统的学习路线。每个人都可以遵循这个大方向。

路线对应学习视频

同时,还根据成长路线提供了每个部分的支持视频。

2视频配套工具国内外网安书籍、文档

工具

视频

书籍

由于资源比较敏感,所以需要的资源并没有完全显示在底部。

简历模板

由于篇幅有限且信息较为敏感,我们仅展示部分信息。

#关于上述#{}如何防止SQL注入?_sql相关内容来源网络仅供参考。相关信息请参见官方公告。

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92000.html

(0)
CSDN的头像CSDN
上一篇 2024年6月24日
下一篇 2024年6月24日

相关推荐

发表回复

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