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

#{}如何防止SQL注入的?它的底层原理是什么?_sqldelete from user where id‘${value}’ 如果我传递的是:1 or 11; –,结果会是什么样,我想大家应该已

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

#mysql日志存储位置

General_log_file=\”D:/query.log\”

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

**2)重启MySQL服务(以管理员身份运行):**

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

停止我的sql

网络启动mysql

使用mybatis分别运行以下两条SQL语句:

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

查看MySQL日志。

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

1.5 `#{}` 和`${}` 的应用场景

`#{}` 比`${}` 好得多,那么为什么`${}` 仍然存在呢?

其实“${}”也是有用途的。我们都知道“${}”连接字符串以产生一个新字符串。

1.5.1 ${} 和#{} 的用法区别

例如,需要通过模糊查询查询用户表中所有姓张的员工信息。

SQL语句是: `从名称类似\’张%\’的用户中选择*`

**此时,如果传递的参数是“Zhang”**

使用`${}` 时: `select * from user where name like \’${value}%\’`

生成的SQL 语句:`select * from user where name like \’张%\’`

哪个兄弟不知道你可以提前回答网络安全面试问题?我们整理了160多道网络安全面试题(金9银10),帮助你在网络安全面试包中脱颖而出。一周去做这件事。

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

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

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

***93 网络安全面试问题***

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

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

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

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

### 推荐的黑客学习资源

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

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

#### 1从基础零开始

##### 学习路线

对于从未接触过网络安全的同学,我们准备了详细的**学习与成长路线图**。这可以说是最科学、最系统的学习路线。大家按照这个大方向走是没有问题的。

![图片](https://img-blog.csdnimg.cn/img_convert/acb3c4714e29498573a58a3c79c775da.gif#pic_center)

##### 路线兼容学习视频

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

![image-20231025112050764](https://img-blog.csdnimg.cn/874ad4fd3dbe4f6bb3bff17885655014.png#pic_center)

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

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

Like (0)
CSDN的头像CSDN
Previous 2024年6月24日
Next 2024年6月24日

相关推荐

发表回复

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