动态 SQL 防止注入的核心原则是:永远不要把用户输入直接拼接到 SQL 语句中。下面从原理到实践系统说明。
动态 SQL 如果这样写:
"SELECT * FROM user WHERE name = '" + userName + "'"
用户输入:
' OR '1'='1
最终 SQL 变成:
SELECT * FROM user WHERE name = '' OR '1'='1'
就会绕过条件,造成注入。
String sql = "SELECT * FROM user WHERE name = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, userName);
✅ 参数永远被视为“数据”,不会被当作 SQL 执行
正确写法(推荐)
<select id="getUser">
SELECT * FROM user
WHERE name = #{name}
</select>
#{} → 预编译参数(安全)
错误写法(危险)
WHERE name = '${name}'
${} → 字符串拼接(极易注入)
QueryWrapper<User> qw = new QueryWrapper<>();
qw.eq("name", userName);
底层使用参数化,安全。
List<String> allowed = Arrays.asList("id", "name", "create_time");
if (!allowed.contains(sortField)) {
throw new IllegalArgumentException("非法字段");
}
ORDER BY ${safeField}
Map<String, String> map = Map.of("时间", "create_time");
String column = map.get(input);
Integer.parseInt()true/falseDateTimeFormatter| 手段 | 说明 |
|---|---|
| 输入校验 | 长度、格式、正则 |
| 最小权限 | DB 账号只给必要权限 |
| WAF | 网络层防护 |
| 关闭错误回显 | 防止信息泄露 |
⚠️ 这些不能替代参数化
动态 SQL 防注入 = 参数化优先 + 动态结构用白名单
如果你用的是 MyBatis / JPA / 某种具体框架,我可以给你更针对性的写法。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。