Mybatis这个框架在日常开发中用的很多,比如面试中经常有一个问题:$#的区别,它们的区别是使用#可以防止SQL注入,今天就来看一下它是如何实现SQL注入的。

什么是SQL注入

在讨论怎么实现之前,首先了解一下什么是SQL注入,我们有一个简单的查询操作:根据id查询一个用户信息。它的sql语句应该是这样:select * from user where id = 。我们根据传入条件填入id进行查询。

如果正常操作,传入一个正常的id,比如说2,那么这条语句变成select * from user where id =2。这条语句是可以正常运行并且符合我们预期的。

但是如果传入的参数变成 '' or 1=1,这时这条语句变成select * from user where id = '' or 1=1。让我们想一下这条语句的执行结果会是怎么?它会将我们用户表中所有的数据查询出来,显然这是一个大的错误。这就是SQL注入。

Mybatis如何防止SQL注入

在开头讲过,可以使用#来防止SQL注入,它的写法如下:

<select id="safeSelect" resultMap="testUser">
SELECT * FROM user where id = #{id}
</select>

在mybatis中查询还有一个写法是使用$,它的写法如下:

<select id="unsafeSelect" resultMap="testUser">
select * from user where id = ${id}
</select>

当我们在外部对这两个方法继续调用时,发现如果传入安全的参数时,两者结果并无不同,如果传入不安全的参数时,第一种使用#的方法查询不到结果(select * from user where id = '' or 1=1),但这个参数在第二种也就是$下会得到全部的结果。

并且如果我们将sql进行打印,会发现添加#时,向数据库执行的sql为:select * from user where id = ' \'\' or 1=1 ',它会在我们的参数外再加一层引号,在使用$时,它的执行sql是select * from user where id = '' or 1=1

弃用$可以吗

我们使用#也能完成$的作用,并且使用$还有危险,那么我们以后不使用$不就行了吗。

并不是,它只是在我们这种场景下会有问题,但是在有一些动态查询的场景中还是有不可代替的作用的,比如,动态修改表名select * from ${table} where id = #{id}。我们就可以在返回信息一致的情况下进行动态的更改查询的表,这也是mybatis动态强大的地方。

如何实现SQL注入的,不用Mybatis怎么实现

其实Mybatis也是通过jdbc来进行数据库连接的,如果我们看一下jdbc的使用,就可以得到这个原因。

#使用了PreparedStatement来进行预处理,然后通过set的方式对占位符进行设置,而$则是通过Statement直接进行查询,当有参数时直接拼接进行查询。

所以说我们可以使用jdbc来实现SQL注入。

看一下这两个的代码:

public static void statement(Connection connection) {
System.out.println("statement-----");
String selectSql = "select * from user";
// 相当于mybatis中使用$,拿到参数后直接拼接
String unsafeSql = "select * from user where id = '' or 1=1;";
Statement statement = null;
try {
statement = connection.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
try {
ResultSet resultSet = statement.executeQuery(selectSql);
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("---****---");
try {
ResultSet resultSet = statement.executeQuery(unsafeSql);
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
} public static void preparedStatement(Connection connection) {
System.out.println("preparedStatement-----");
String selectSql = "select * from user;";
//相当于mybatis中的#,先对要执行的sql进行预处理,设置占位符,然后设置参数
String safeSql = "select * from user where id =?;";
PreparedStatement preparedStatement = null;
try {
preparedStatement = connection.prepareStatement(selectSql);
ResultSet resultSet = preparedStatement.executeQuery();
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("---****---");
try {
preparedStatement = connection.prepareStatement(safeSql);
preparedStatement.setString(1," '' or 1 = 1 ");
ResultSet resultSet = preparedStatement.executeQuery();
print(resultSet);
} catch (SQLException e) {
e.printStackTrace();
}
} public static void print(ResultSet resultSet) throws SQLException {
while (resultSet.next()) {
System.out.print(resultSet.getString(1) + ", ");
System.out.print(resultSet.getString("name") + ", ");
System.out.println(resultSet.getString(3));
}
}

总结

  • Mybatis中使用#可以防止SQL注入,$并不能防止SQL注入
  • Mybatis实现SQL注入的原理是调用了jdbc中的PreparedStatement来进行预处理。

本文由博客一文多发平台 OpenWrite 发布!

博主邮箱:liunaijie1996@163.com,有问题可以邮箱交流。

Mybatis是如何实现SQL防注入的的更多相关文章

  1. SQL防注入程序 v1.0

    /// ***************C#版SQL防注入程序 v1.0************ /// *使用方法: /// 一.整站防注入(推荐) /// 在Global.asax.cs中查找App ...

  2. PHP之SQL防注入代码集合(建站常用)

    SQL防注入代码一 <?php if (!function_exists (quote)) { function quote($var) { if (strlen($var)) { $var=! ...

  3. sql 防注入 维基百科

    http://zh.wikipedia.org/wiki/SQL%E8%B3%87%E6%96%99%E9%9A%B1%E7%A2%BC%E6%94%BB%E6%93%8A SQL攻击(SQL inj ...

  4. 特殊字符的过滤方法,防sql防注入代码的过滤方法

    特殊字符的过滤方法 function strFilter($str){ //特殊字符的过滤方法 $str = str_replace('`', '', $str); $str = str_replac ...

  5. SQL防注入程序

    1.在Global.asax.cs中写入: protected void Application_BeginRequest(Object sender,EventArgs e){      SqlIn ...

  6. PHP SQL防注入

    过年前后在做一个抽奖的东西,需要用户填写中奖信息,为了防止非法用户对数据库进行入侵神马的,于是写下基本的防注入语句,需要用的可以自己封装成一个function. $str = str_replace( ...

  7. 360提供的SQL防注入

    <?php class sqlsafe { private $getfilter = "'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\ ...

  8. .net sql 防注入 httpmodule

    1 新建一个类,实现IHttpModule接口 using System; using System.Collections.Generic; using System.Linq; using Sys ...

  9. PHP之SQL防注入代码(360提供)

    <?php class sqlsafe { private $getfilter = "'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\ ...

随机推荐

  1. day7_python之面向对象item系列(__getitem__,__setitem__,__delitem__)

    class Foo: def __getitem__(self, item): print('=====>get') return self.__dict__[item] def __setit ...

  2. uva 10566 Crossed Ladders (二分)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  3. 云原生生态周报 Vol. 6 | KubeCon EU 特刊

    5 月 26日,2019 年第一个 KubeCon + CloudNativeCon 在巴塞罗那成功闭幕.本届 KubeCon 共吸引了超过 7700 名与会者,相较去年哥本哈根大会的 4300 余名 ...

  4. centos安装hdp

    1. 准备6和7的 YUM源包 1.1 centos 下载后解压到同一个目录 http://mirrors.163.com/centos/6/isos/x86_64/CentOS-6.9-x86_64 ...

  5. 原生sql和 TP sql怎么关联?

    整合后

  6. HDU 1114 完全背包问题

    题意:有一个存钱罐,空罐时的重量是e,满罐时的重量是f,现在有n种硬币,每一种有无限个,现在给出每一种硬币的价值p和重量w,问存钱罐中最少钱,输出最小钱,否则输出... 思路:变形的完全背包问题,只是 ...

  7. 常用的python内建函数

    raw_input() 函数说明 函数签名:raw_input([prompt]) 使用形式如下: raw_input([prompt]) -> string 如果提供了参数prompt,就会在 ...

  8. 深入java面向对象三:抽象类和接口(转载)

    文章系转载,地址: http://blog.csdn.net/xw13106209/article/details/6923556 1.概述     一个软件设计的好坏,我想很大程度上取决于它的整体架 ...

  9. 2018-9-1-win2d-画出好看的图形

    title author date CreateTime categories win2d 画出好看的图形 lindexi 2018-09-01 16:25:40 +0800 2018-2-13 17 ...

  10. python基础七之集合

    集合:可变的数据类型,他里面的元素必须是不可变的数据类型,无序,不重复. 增加 set1 = {'zxc', 'zxf'} set1.add('zxv') # 无序添加 set1.update('zx ...