MyBatis中 #{} 与 ${} 的区别

隐身守侯 提交于 2019-12-10 08:32:24

#{} 在一定程度上防止了SQL注入

使用#{}入参,MyBatis会生成PrepareStatement并且可以安全地设置参数(=?)的值。因为sql语句已经预编译好了,传入参数的时候,不会重新生产sql语句。安全性高。
JDBC中PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。

//PreparedStatement预编译
Connection conn = getConn();//获得连接
String sql = "select username, password from user where username=? and password=?"; //执行sql前会预编译号该条语句
PreparedStatement pstmt = conn.prepareStatement(sql); 
pstmt.setString(1,"username"); 
pstmt.setString(2, "password");
ResultSet rs=pstmt.executeUpdate(); 

#将传入的数据都当成一个字符串,会对自动传入的数据加一个引号。

--XML配置SQL语句
SELECT * FROM user WHERE username=#{username}

如果传入的值是 123 ,那么解析成sql时的值为 WHERE username=‘111’,如果传入的值是id,则解析成的sql为WHERE username=‘id’。

${} 如果不对传入参数进行拦截检测,存在很严重的SQL注入问题

XML{} 将传入的数据直接替换XML中配置的{username}等。没有对SQL进行预编译。存在很严重的SQL注入问题。
如:

--XML配置SQL语句
SELECT * FROM user WHERE username=${username} AND password=${password}

如果入参为username=‘AAA’,password=‘aaa’ 在执行时他会将传入的参数username,password替换掉 ${username}。如以下mybatis的日志

### The error may exist in file [E:\JavaWebitems\zxGitee\zxTest-java\target\classes\mybatis-plus\mapping\UserMapping.xml]
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT *  FROM user  WHERE username = AAA AND password = aaa
### Cause: java.sql.SQLSyntaxErrorException: Unknown column 'AAA' in 'where clause' ; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: Unknown column 'AAA' in 'where clause'] with root cause

是JDBC中拼接SQL语句的方式

private String getNameByUserId(String username,String password) {
    Connection conn = getConn();//获得连接
   String sql = "select username, password from user where username="+username+" and password="+password;
    PreparedStatement pstmt =  conn.prepareStatement(sql);
    ResultSet rs=pstmt.executeUpdate();
}

这样存在很严重的SQL注入问题,举个简答的例子,传入的参数为 username=‘AAA’–,password=随便写
执行的SQL变为

SELECT * FROM user WHERE username='AAA'-- AND password=随便写

username='AAA’后面的SQL语句被注释掉,不需要密码就可以轻松登录。

结论

在编写MyBatis的映射语句时,尽量采用“#{xxx}”这样的格式。若不得不使用“${xxx}”这样的参数,要手工地做好过滤工作,来防止SQL注入攻击。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!