mybatis-plus apply 防SQL注入

1,181 阅读3分钟

MyBatis-Plus 提供了 apply 方法,用于在查询条件中直接拼接自定义的 SQL 片段。然而,直接拼接 SQL 片段可能会导致 SQL 注入 风险。为了避免 SQL 注入,需要谨慎处理用户输入,并使用参数化查询或 MyBatis-Plus 提供的安全方法。


1. apply 方法的作用

apply 方法用于在查询条件中拼接自定义的 SQL 片段。例如:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", "2023-10-01");

这里的 {0} 是占位符,MyBatis-Plus 会自动将其替换为参数值。


2. SQL 注入风险

如果直接将用户输入拼接到 SQL 片段中,可能会导致 SQL 注入。例如:

String userInput = "2023-10-01'; DROP TABLE user; --";
queryWrapper.apply("date_format(create_time, '%Y-%m-%d') = '" + userInput + "'");

生成的 SQL 可能会变成:

date_format(create_time, '%Y-%m-%d') = '2023-10-01'; DROP TABLE user; --'

这将导致严重的 SQL 注入问题。


3. 防止 SQL 注入的方法

方法 1:使用占位符和参数化查询

MyBatis-Plus 的 apply 方法支持占位符(如 {0}{1}),并会自动对参数进行转义,从而防止 SQL 注入。

String safeDate = "2023-10-01";
queryWrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", safeDate);

生成的 SQL 是安全的:

date_format(create_time, '%Y-%m-%d') = '2023-10-01'

方法 2:使用 SqlInjectionUtils 检查输入

MyBatis-Plus 提供了 SqlInjectionUtils 工具类,可以用于检查输入是否包含 SQL 注入风险。

import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils;

String userInput = "2023-10-01'; DROP TABLE user; --";
if (SqlInjectionUtils.check(userInput)) {
    throw new IllegalArgumentException("输入包含非法字符");
}
queryWrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", userInput);

方法 3:避免直接拼接 SQL

尽量避免直接拼接 SQL 片段,而是使用 MyBatis-Plus 提供的安全方法。例如,使用 eqlike 等方法:

queryWrapper.eq("date_format(create_time, '%Y-%m-%d')", "2023-10-01");

4. 最佳实践

  1. 始终使用占位符

    • 使用 {0}{1} 等占位符,而不是直接拼接字符串。
  2. 验证用户输入

    • 对用户输入进行严格的验证和过滤,确保其符合预期格式。
  3. 使用安全的 API

    • 尽量使用 MyBatis-Plus 提供的安全方法(如 eqlike 等),而不是直接拼接 SQL。
  4. 定期检查代码

    • 定期检查代码中是否存在直接拼接 SQL 的情况,及时修复潜在的安全问题。

5. 示例代码

安全使用 apply 方法:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
String safeDate = "2023-10-01";
queryWrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", safeDate);
List<User> userList = userMapper.selectList(queryWrapper);

不安全使用 apply 方法(不推荐):

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
String unsafeDate = "2023-10-01'; DROP TABLE user; --";
queryWrapper.apply("date_format(create_time, '%Y-%m-%d') = '" + unsafeDate + "'");
List<User> userList = userMapper.selectList(queryWrapper);

6. 总结

  • apply 方法可以安全使用,但必须通过占位符和参数化查询来避免 SQL 注入。
  • 避免直接拼接 SQL,始终对用户输入进行验证和过滤。
  • 使用 MyBatis-Plus 提供的工具类(如 SqlInjectionUtils)来检查输入的安全性。
  • 遵循最佳实践,确保代码的安全性和可维护性。