MyBatis传参的时候 # 和 $ 有何区别,哪个可以防注入,防注入的原理是啥?jdbc是如何防sql注入的

MyBatis传参的时候 # 和 $ 有何区别

1)#方式能够很大程度防止sql注入,Mybatis会把这个参数认为是一个字符串,直接转为字符串。
2)$ 方式一般用于传入数据库对象,例如传入表名、字段名,$方式的参数会直接参与SQL编译,从而不能避免注入攻击,无法防止 Sql注入
3)从安全性上考虑,能使用#尽量使用#来传参,因为这样可以有效防止SQL注入的问题。使用 # 引用参数的时候,例如传入参数是param=“WeBank”,那么在SQL(Select * from tmp where name = #{param}) 使用的时候就会转换为Select * from tmp where name = 'WeBank'; ;同时在SQL Select * from tmp where name = ${param} 使用的时候就会转换为 Select * from tmp where name = WeBank

MyBatis是如何做到防止sql注入的

MyBatis框架作为一款半自动化的持久层框架,其SQL语句都要我们自己手动编写,这个时候当然需要防止SQL注入。其实,MyBatis的SQL是一个具有“输入+输出”的功能,类似于函数的结构,参考上面的两个例子。其中,parameterType表示了输入的参数类型,resultType表示了输出的参数类型。回应上文,如果我们想防止SQL注入,理所当然地要在输入参数上下功夫。上面代码中使用#的即输入参数在SQL中拼接的部分,传入参数后,打印出执行的SQL语句,会看到SQL是这样的:
select id, username, password, role from user where username=? and password=?
不管输入什么参数,打印出的SQL都是这样的。这是因为MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。

底层实现原理

MyBatis是如何做到SQL预编译的呢?其实在框架底层,是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。

	 //安全的,预编译了的 获得连接
	Connection conn = getConn();
	//执行sql前会预编译号该条语句
	String sql = "select id, name from user where id=? "; 
	PreparedStatement pstmt = conn.prepareStatement(sql); 
	pstmt.setString(1, id); 
	ResultSet rs=pstmt.executeUpdate(); 
	//不安全的,没进行预编译  获得连接
    Connection conn = getConn();
    String sql = "select id,name from user where id=" + id;
    //当id参数为"12345; drop table user;"时,执行的sql语句如下:
    //select id,name from user where id=12345; drop table user;  
    PreparedStatement pstmt =  conn.prepareStatement(sql);
    ResultSet rs=pstmt.executeUpdate();
    ......

猜你喜欢

转载自blog.csdn.net/lxn1023143182/article/details/114291975