防止SQL注入的核心是使用PreparedStatement和参数化查询,避免用户输入拼接SQL。通过预编译将SQL结构与数据分离,确保输入仅作数据处理;动态SQL需用白名单校验表名、字段等;优先使用ORM框架的参数化功能(如MyBatis的#{}),避免${}字符串替换;辅以输入校验(长度、格式、特殊字符过滤)增强安全。关键在于不拼接、全参数化、严校验。

防止 SQL 注入的核心是避免将用户输入直接拼接到 SQL 语句中。在 Java 中,最有效的方式是使用预编译语句(PreparedStatement)和参数化查询。
使用 PreparedStatement 进行参数化查询
PreparedStatement 能够将 SQL 结构与参数数据分离,数据库会预先解析 SQL 模板,用户输入仅作为数据处理,不会改变原有逻辑。
例如,以下代码存在风险:
String sql = "SELECT * FROM users WHERE username = '" + username + "'";攻击者可通过输入 ' OR '1'='1 来绕过验证。
立即学习“Java免费学习笔记(深入)”;
正确做法:
String sql = "SELECT * FROM users WHERE username = ?"; PreparedStatement pstmt = connection.prepareStatement(sql); pstmt.setString(1, username); ResultSet rs = pstmt.executeQuery();
占位符 ? 会强制参数以数据形式传入,不参与 SQL 解析。
避免动态拼接 SQL 字符串
不要将用户输入直接拼接到 SQL 中,包括表名、字段名、排序字段等。如果必须动态生成 SQL,应使用白名单机制校验输入。
比如排序字段只能是预定义的几个字段:
- 允许字段:name, age, created_time
- 检查输入是否在允许列表中
- 不在则使用默认值或拒绝请求
使用 ORM 框架(如 MyBatis、Hibernate)
主流 ORM 框架默认支持参数化查询。只要不使用原生 SQL 或拼接方式,风险较低。
MyBatis 示例:
#{username} 会被自动转为 PreparedStatement 参数,#{} 是安全的,${} 则是字符串替换,有注入风险,应避免用于用户输入。
对输入进行校验和过滤
虽然不能完全依赖输入检查,但合理校验可增加安全性。
- 长度限制:用户名不超过 50 字符
- 格式校验:邮箱、手机号使用正则匹配
- 特殊字符处理:对无法避免的动态内容,过滤或转义单引号、分号等敏感字符(但不如参数化可靠)
基本上就这些。关键点是坚持使用 PreparedStatement 和参数化查询,不拼接 SQL,再配合输入校验和框架规范,就能有效杜绝 SQL 注入。










