发布网友
共5个回答
懂视网
前言略,直奔主题..
#{}相当于jdbc中的preparedstatement
${}是输出变量的值
简单的说就是#{}传过来的参数带单引号‘‘,而${}传过来的参数不带单引号。
你可能说不明所以,不要紧我们看2段代码:
String sql = "select * from admin_domain_location order by ?"; PreparedStatement st = con.prepareStatement(sql); st.setString(1, "domain_id"); System.out.println(st.toString());
ResultSet rs = st.executeQuery();
while(rs.next()){
System.out.println(rs.getString("domain_id"));
}
输出结果:
com.mysql.jdbc.PreparedStatement@1fa1ba1: select * from admin_domain_location order by ‘domain_id‘
3
4
5
2
6
这是个jdbc的preparedstatement例子,不要吐槽我这么写是否合法,这里只是为了说明问题.
以上例子有得出以下信息: 1) order by后面如果采用预编译的形式动态输入参数,那么实际插入的参数是一个字符串,例子中是:order by ‘domain_id‘
2)输出结果并没有排序,从sql语句中的形式我们也可以推测出此sql语句根本也不合法(正常应该是 order by domain_id )
修改以上代码如下:
String input = "domain_id"; String sql = "select * from admin_domain_location order by "+input; PreparedStatement st = con.prepareStatement(sql); System.out.println(st.toString()); ResultSet rs = st.executeQuery(); while(rs.next()){ System.out.println(rs.getString("domain_id")); } 输出结果:
com.mysql.jdbc.PreparedStatement@1fa1ba1: select * from admin_domain_location order by domain_id
2
3
4
5
6
此次我们直接把一个变量的值拼接sql语句,从结果可以看出来:
1)sql语句拼接正常
2)查询结果排序正常
你可能要问这和#{}与${}有什么关系..
上面已经说过#{}相当于jdbc的preparedstatement,所以以上的第一个例子就相当于#{},那么第二个例子就自然而然指的是${}的情况.
你可能说思维还是有些凌乱,不要紧我们来看第三个例子:
String sql = "select * from admin_domain_location where domain_id=?"; PreparedStatement st = con.prepareStatement(sql); st.setString(1, "2"); System.out.println(st.toString()); ResultSet rs = st.executeQuery(); while(rs.next()){ System.out.println(rs.getString("domain_id")); } ======================================= String input = "2"; String sql = "select * from admin_domain_location where domain_id=‘"+input+"‘"; PreparedStatement st = con.prepareStatement(sql); System.out.println(st.toString()); ResultSet rs = st.executeQuery(); while(rs.next()){ System.out.println(rs.getString("domain_id")); } 输出结果都为: com.mysql.jdbc.PreparedStatement@12bf560: select * from admin_domain_location where domain_id=‘2‘ 2
这第三个例子虽然说的是#{}和${}通用的问题,也就是说在此种情况下#{}和${}是通用的,只不过需要些小的转换.如例子中需要手动
拼接单引号 ‘ ‘ 到变量值的前后,确保sql语句正常.
简单说#{}是经过预编译的,是安全的,而${}是未经过预编译的,仅仅是取变量的值,是非安全的,存在sql注入.
这里先说一下只能${}的情况,从我们前面的例子中也能看出,order by是肯定只能用${}了,用#{}会多个‘ ‘导致sql语句失效.此外还有一个like 语句后也需要用${},简单想一下
就能明白.由于${}仅仅是简单的取值,所以以前sql注入的方法适用此处,如果我们order by语句后用了${},那么不做任何处理的时候是存在sql注入危险的.你说怎么防止,那我只
能悲惨的告诉你,你得手动处理过滤一下输入的内容,如判断一下输入的参数的长度是否正常(注入语句一般很长),更精确写查询一下输入的参数是否在预期的参数集合中..
mybatis中#{}和${}的区别及order by的sql注入问题
标签:
热心网友
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
字符串替换
默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速也是首选做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用:
ORDER BY ${columnName}
这里MyBatis不会修改或转义字符串。
重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。
mybatis本身的说明:
?
1
2
3
4
5
String Substitution
By default, using the #{} syntax will cause MyBatis to generate PreparedStatement properties and set the values safely against the PreparedStatement parameters (e.g. ?). While this is safer, faster and almost always preferred, sometimes you just want to directly inject a string unmodified into the SQL Statement. For example, for ORDER BY, you might use something like this:
ORDER BY ${columnName}
Here MyBatis won't modify or escape the string.
NOTE It's not safe to accept input from a user and supply it to a statement unmodified in this way. This leads to potential SQL Injection attacks and therefore you should either disallow user input in these fields, or always perform your own escapes and checks.
从上文可以看出:
1. 使用#{}格式的语法在mybatis中使用Preparement语句来安全的设置值,执行sql类似下面的:
?
1
2
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1,id);
这样做的好处是:更安全,更迅速,通常也是首选做法。
2. 不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用:
?
1
ORDER BY ${columnName}
此时MyBatis 不会修改或转义字符串。
这种方式类似于:
?
1
2
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
这种方式的缺点是:
以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。
热心网友
#相当于对数据 加上 双引号,$相当于直接显示数据
#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
$将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
热心网友
Bee框架不会有这个问题.可以尝试下,多一个选择.
Bee框架:一个十分钟即可学会的ORM框架。它不用每操作一个数据库表,就要编写一次代码,省时/优雅、简易、自动( Tea: Timesaving/Tasteful, Easy, Automatic) ,开发效率极高,编码复杂度为O(1).
一个开发成本和开发速度都不比php差的java ORM框架。
热心网友
$是拼接sql,#是传参