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 提供的安全方法。例如,使用 eq、like 等方法:
queryWrapper.eq("date_format(create_time, '%Y-%m-%d')", "2023-10-01");
4. 最佳实践
-
始终使用占位符:
- 使用
{0}、{1}等占位符,而不是直接拼接字符串。
- 使用
-
验证用户输入:
- 对用户输入进行严格的验证和过滤,确保其符合预期格式。
-
使用安全的 API:
- 尽量使用 MyBatis-Plus 提供的安全方法(如
eq、like等),而不是直接拼接 SQL。
- 尽量使用 MyBatis-Plus 提供的安全方法(如
-
定期检查代码:
- 定期检查代码中是否存在直接拼接 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)来检查输入的安全性。 - 遵循最佳实践,确保代码的安全性和可维护性。