SQL 注入防护进阶:MyBatis #{} 和 ${} 的区别——不止是预编译
引言 去年做代码安全审计,SpotBugs 报了一个 SQL_INJECTION 告警,定位过去一看: <select id="listOrders" resultType="Order"> SELECT * FROM orders WHERE status = #{status} ORDER BY ${sortColumn} ${sortOrder} </select> 开发同事很委屈:"WHERE 条件我全部用的 #{} 预编译啊,注入不了!"我问他:如果 sortColumn 传入 (CASE WHEN (SELECT 1=1) THEN id ELSE status END),这条 SQL 会发生什么?他愣住了。 测试一下:请求带上 sortColumn=(CASE WHEN (substr(database(),1,1)='p') THEN id ELSE create_time END),接口返回的排序结果不一样——攻击者可以通过排序结果的变化,一个字符一个字符把数据库名、表名、数据全部拖走。这就是经典的 ORDER BY 注入,也是绝大多数 My....