MyBatis的`${}`和`#{}`的区别及SQL防注入的方法

简介: 本文介绍了MyBatis的`${}`和`#{}`的用法区别,以及针对$可能带来的风险提供一种简易的SQL防注入的方法。

本文介绍了MyBatis的${}#{}的用法区别,以及针对$可能带来的风险提供一种简易的SQL防注入的方法。

#{}用法

select语句是MyBatis中最常用的元素之一,例如:

<select id="selectPerson" parameterType="int" resultType="hashmap">

SELECT * FROM PERSON WHERE ID = #{id}

</select>

此语句称为selectPerson,采用int(或Integer)类型的参数,并将查询结果封装为HashMap作为返回。

语句中#{id}这告诉MyBatis创建一个PreparedStatement参数。对于JDBC而言,这样的参数类似于PreparedStatement语句中的“?”标识,如下:

// JDBC代码
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";

PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

${}用法

默认情况下,使用#{}语法将导致MyBatis生成PreparedStatement属性,并根据PreparedStatement参数安全地设置值(例如“?”标识)。虽然这更安全、更快,而且几乎总是首选,但有时只是想直接将未修改的字符串注入SQL语句。例如,对于订单排序,可以使用类似的内容:

ORDER BY ${columnName}

在上面的用法中,MyBatis不会修改或转义字符串。

但需要注意的是: ${}用法如果是直接接受用户的输入,将未经修改的语句注入到程序是不安全的。这将导致潜在的SQL注入攻击风险。

针对${}的SQL防注入器

${}用法存在SQL注入的风险,因此需要对用户的输入内容进行校验。这里提供一个简易的SQL防注入的方法。

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SQL注入防护器
 *
 * @author waylau.com
 * @since 2021-04-18
 */
public class SqlInjectionProtector {
    private static final String SPECIAL_CHAR = "\\W";

    /**
     * 校验SQL语句是否合法
     * 如果非法,则抛出异常
     *
     * @param statement 语句
     * @return 是否合法
     * @throws IllegalArgumentException 校验非法则抛出此异常
     */
    public static boolean verifySqLStatement(String statement) {
        if (!StringUtility.isEmpty(statement)) {
            if (isSpecialChar(statement)) {
                throw new IllegalArgumentException("illegal statement: " + statement);
            }
        }

        return Boolean.TRUE;
    }

    /**
     * 判断是否含有特殊字符
     *
     * @param str 校验的字符串
     * @return 是否特殊字符
     */
    public static boolean isSpecialChar(String str) {
        Pattern pattern = Pattern.compile(SPECIAL_CHAR);
        Matcher matcher = pattern.matcher(str);
        return matcher.find();
    }

}

上述代码核心思想是,通过正则表达式的方式,来检测出特殊字符。有特殊字符,就抛出异常,中断程序继续往下运行。

何为特殊字符?针对ORDER BY ${columnName} 这个例子而言,字段名的所使用的字符是有一定限制的,限制只能使用[a-z0-9A-Z_]这个范围内的字符。因此超出这个范围内的所有字符,即为特殊字符。在正则表达式里面,非[a-z0-9A-Z_]范围内的字符,可以用“\W”表示。

以下是测试用例

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

/**
* SqlInjectionProtector Test
*
* @author waylau.com
* @since 2021-04-18
*/
public class SqlInjectionProtectorTest {

    @Test
    public void testIsSpecialChar() {
        assertFalse(SqlInjectionProtector.isSpecialChar("user_name"));
        assertTrue(SqlInjectionProtector.isSpecialChar("user_name!"));
        assertTrue(SqlInjectionProtector.isSpecialChar("user_name@"));
        assertTrue(SqlInjectionProtector.isSpecialChar("user_name^"));
        assertTrue(SqlInjectionProtector.isSpecialChar("user_name ")); // 空格
        assertTrue(SqlInjectionProtector.isSpecialChar("insert\ninto\nuser_t")); // 换行符
        assertTrue(SqlInjectionProtector.isSpecialChar("user_name|user_t"));
    }

    @Test
    public void testVerifySqLStatement() {
        assertTrue(SqlInjectionProtector.verifySqLStatement("user_name"));
    }
}

参考引用

目录
相关文章
|
2月前
|
SQL 监控 安全
Flask 框架防止 SQL 注入攻击的方法
通过综合运用以上多种措施,Flask 框架可以有效地降低 SQL 注入攻击的风险,保障应用的安全稳定运行。同时,持续的安全评估和改进也是确保应用长期安全的重要环节。
157 71
|
19天前
|
SQL XML Java
mybatis实现动态sql
MyBatis的动态SQL功能为开发人员提供了强大的工具来应对复杂的查询需求。通过使用 `<if>`、`<choose>`、`<foreach>`等标签,可以根据不同的条件动态生成SQL语句,从而提高代码的灵活性和可维护性。本文详细介绍了动态SQL的基本用法和实际应用示例,希望对您在实际项目中使用MyBatis有所帮助。
47 11
|
2月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
2月前
|
SQL 安全 PHP
PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全
本文深入探讨了PHP开发中防止SQL注入的方法,包括使用参数化查询、对用户输入进行过滤和验证、使用安全的框架和库等,旨在帮助开发者有效应对SQL注入这一常见安全威胁,保障应用安全。
68 4
|
2月前
|
SQL 安全 前端开发
Web学习_SQL注入_联合查询注入
联合查询注入是一种强大的SQL注入攻击方式,攻击者可以通过 `UNION`语句合并多个查询的结果,从而获取敏感信息。防御SQL注入需要多层次的措施,包括使用预处理语句和参数化查询、输入验证和过滤、最小权限原则、隐藏错误信息以及使用Web应用防火墙。通过这些措施,可以有效地提高Web应用程序的安全性,防止SQL注入攻击。
65 2
|
2月前
|
SQL BI 数据库
SQL操作的一些基本方法
【10月更文挑战第27天】SQL操作的一些基本方法
45 3
|
2月前
|
SQL 监控 固态存储
SQL优化有哪些方法?
【10月更文挑战第27天】SQL优化有哪些方法?
54 3
|
2月前
|
SQL 安全 Java
MyBatis(6)#{}和${}的区别
在MyBatis中,`#{}`和`${}`是用于在SQL语句中嵌入参数的两种方式。`#{}`用于预处理参数,可以防止SQL注入;而`${}`进行直接字符串替换,适用于动态插入表名或列名,但存在SQL注入风险。建议优先使用`#{}`,并在必要时谨慎使用`${}`。
|
2月前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
3月前
|
SQL 安全 关系型数据库
SQL语句中表名通配符的使用技巧与方法
在SQL查询中,通配符通常用于匹配字符串数据,如列值中的部分字符