怎样解决MyBatis中$符号带来的SQL注入风险_替换为#预编译占位符
怎样解决MyBatis中$符号带来的SQL注入风险?关键在于厘清场景

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
一提到MyBatis中的${}和SQL注入,很多人的第一反应是:“把它换成#{}不就行了?”
其实,这个想法恰恰是问题的开始。真相是:绝大多数情况下,${}不能直接“替换为”#{}——强行替换会导致SQL语法错误,程序根本跑不起来。真正的解决之道,在于搞清楚三个核心问题:哪些地方是误用了${}?哪些地方又不得不用${}?以及在那些必须用的场景下,如何守住安全底线。
哪些地方误用了${}?这是最常见的漏洞源头
生产环境里,绝大部分SQL注入漏洞都源于此。典型表现是:参数本应是纯粹的数据值(比如用户ID、搜索关键词、订单金额),却被错误地用${}拼接进了WHERE、INSERT或UPDATE子句中。
- 错误写法示例:
WHERE name = '${name}'或者AND status = ${status} - 后果有多严重?如果用户传入
name="admin' OR '1'='1",SQL就会变成WHERE name = 'admin' OR '1'='1',直接导致全表数据泄露。 - 正确做法:统一改为
WHERE name = #{name}和AND status = #{status}。 - 这里有个细节:
#{}会自动处理类型,字符串会加引号,数字或布尔值会做对应转换,完全不需要手动拼接单引号。
哪些地方必须用${}?#{}真的无能为力
为什么不能全用#{}?因为它的底层是JDBC的PreparedStatement,所有参数都会被当作“值”来处理,并加上引号或进行类型绑定。而SQL语法中的某些部分,比如表名、字段名、ORDER BY后的排序方向、GROUP BY表达式,它们本身是“标识符”或“关键字”,绝对不能加引号,否则数据库会直接报语法错误。
- 动态表名(如分库分表):
FROM ${tableName}。如果写成FROM #{tableName},就会变成FROM 'user_202604',语法错误。 - 动态排序:
ORDER BY ${sortField} ${sortOrder}。如果字段名用了#{},会变成ORDER BY 'created_time',字段名被当成字符串,排序失效。 - 动态分页的偏移量:
LIMIT ${(page-1)*size}, #{size}。偏移量往往是个表达式,#{}不支持计算,而且偏移量作为数字也不能加引号。
必须用${}时,如何防御注入?白名单校验是唯一靠谱的方案
到了这一步,没有“银弹”。别指望靠过滤几个关键词或者转义单引号就能万事大吉,攻击面太广了(比如UNION SELECT、注释符--、内联注释/* */)。唯一能落地、真正有效的防御策略就是:只允许已知安全的输入。
- 对动态表名:在Ja va层定义合法的表名数组,比如
String[] validTables = {"user", "order_202601", "order_202602"},然后严格校验传入值是否在名单内:Arrays.asList(validTables).contains(tableName)。 - 对排序字段:使用枚举或Map进行映射。例如,建立一个映射关系:
Map.of("ctime", "created_time", "utime", "updated_time")。前端只传递“ctime”这样的key,后端根据映射表转换为真实的数据库字段名。 - 对排序方向:强制限定只能为
"asc"或"desc",其他任何输入一律拒绝,或者提供一个安全的默认值(如"asc")。 - 核心原则:绝对不要将用户原始的、未经检查的输入(无论是HTTP参数还是JSON字段)直接塞进
${}里。这无异于给攻击者递上了一把打开数据库大门的钥匙。
模糊查询(LIKE)场景的典型陷阱与正确解法
这个场景非常典型。很多人为了图省事,会写成LIKE '%${keyword}%',但这正是高危写法。正确的姿势是,让#{}承担传递值的责任,而通配符的逻辑交给数据库函数去处理。
- 错误的高危写法:
WHERE title LIKE '%${keyword}%'。如果keyword="a%b' OR '1'='1",注入将直接穿透。 - 推荐写法(MySQL):
WHERE title LIKE CONCAT('%', #{keyword}, '%')。 - 或Oracle写法:
WHERE title LIKE '%' || #{keyword} || '%'。 - 关键点:通配符
%由数据库的字符串连接函数(如CONCAT)包裹,用户输入的值始终通过#{}走预编译,完全不参与SQL字符串的拼接。
最后,还有一个极易被忽略的“坑”:MyBatis Generator等工具自动生成的XML代码中,片段和ORDER BY子句默认可能使用${}。很多人直接复制使用,却忘了补充白名单校验。记住,只要代码中间出现了${},就必须问自己一句:这个值是完全由我控制的吗?如果答案是否定的,那么就必须在Ja va层加上一层严格的校验或映射转换。这才是守住安全防线的关键所在。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
团队版Navicat专属功能:如何监控管理团队存储用量
Na vicat团队版存储监控的真相:没有仪表盘,只有手动排查与402警报 团队版Na vicat里看不到存储用量统计 如果你正在使用Na vicat团队版,无论是Premium Team还是Cloud Team,首先得接受一个现实:产品本身并没有内置一个直观的“团队存储用量仪表盘”或实时图表。你登
mysql并发更新同一行数据怎么办_利用乐观锁或分段更新优化
MySQL并发更新同一行数据怎么办?利用乐观锁或分段更新优化 先说结论:最稳妥的方案,是优先采用带条件的 UPDATE 配合 ROW_COUNT() 检查,并结合 version 字段实现乐观锁。至于分段更新,它只在批量修正这类少数场景中作为兜底手段,绝不能替代核心的并发控制逻辑。 为什么不能指望
MySQL数据库异构迁移面临的挑战_转换数据类型与存储引擎
MySQL异构迁移:四大核心挑战与实战应对指南 直接说结论:一次成功的MySQL异构迁移,远不止是数据搬运。它更像是一次精密的“器官移植”,需要针对不同“组织”的特性进行预处理。整个过程可以归纳为四类核心问题的系统化处理:时间类型必须按UTC显式转换并规避自动更新陷阱;存储引擎切换应禁用简单的ALT
mysql如何处理mysql服务无法启动_查看error日志排查原因
MySQL服务启动失败?别慌,先看懂error log在说什么 遇到MySQL服务启动失败,很多人的第一反应是重装或者四处搜索错误代码。其实,最直接、最准确的“故障诊断书”就在眼前——那就是MySQL的error log。问题在于,很多人要么找不到它,要么面对满屏的日志信息不知从何看起。今天,我们就
Oracle如何防止DBA误操作删除用户_使用系统触发器保护
角色与核心任务 你是一位顶级的文章润色专家,擅长将AI生成的文本转化为具有个人风格的专业文章。现在,请对用户提供的文章进行“人性化重写”。 你的核心目标是:在不改动原文任何事实信息、核心观点、逻辑结构、章节标题和所有图片的前提下,彻底改变原文的AI表达腔调,使其读起来像是一位资深人类专家的作品。 特
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

