直接拼接sql字符串必然导致sql注入风险,必须使用preparedstatement参数化查询;mybatis中禁用${},仅用#{};输入验证和白名单校验是必要补充,但不可替代参数化。

直接拼接SQL字符串是高危行为
只要代码里出现 String sql = "SELECT * FROM user WHERE name = '" + name + "'" 这类写法,就已暴露SQL注入风险。MySQL不会区分哪部分是逻辑、哪部分是数据,攻击者输入 ' OR '1'='1 会让查询变成恒真条件,绕过认证或清空整张表。
这类拼接常见于老旧代码、动态构建查询(如搜索条件组合)、或误用 Statement 替代 PreparedStatement 的场景。它不是“可能被攻破”,而是“必然可被攻破”——只要输入可控,且未做转义或隔离。
- 永远不要用
+拼接用户输入进SQL语句 - 禁止在DAO层、Service层、Controller层手动拼接SQL
- 即使输入看起来“只含数字”,也不能放松:MySQL支持
0x313233十六进制字面量、CHAR(49,50,51)等绕过方式
必须用 PreparedStatement 设置参数
PreparedStatement 不是“推荐用”,而是Java连接MySQL时防注入的**唯一可靠基础手段**。它的防护原理是:SQL结构提前编译,参数通过独立协议通道传入,数据库引擎天然隔离执行逻辑与数据内容。
正确写法示例:
String sql = "SELECT id, name FROM user WHERE status = ? AND age BETWEEN ? AND ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, status); // 自动处理类型和转义
ps.setInt(2, minAge);
ps.setInt(3, maxAge);
ps.executeQuery();
}
- 占位符
?位置必须与setXxx()调用顺序严格一致 - 不要用
ps.setString(1, "'" + value + "'")—— 这等于手动加引号,反而破坏预编译机制 - 批量操作用
addBatch()+executeBatch(),仍走参数化路径 - 注意:
Connection.prepareStatement()本身不校验SQL语法,错误在executeQuery()时才抛出
MyBatis里必须用 #{},禁用 ${}
MyBatis默认不自动防护,关键在占位符选择:#{} 底层调用 PreparedStatement,${} 是纯字符串替换,等同于手拼SQL。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
典型危险场景:
-
ORDER BY ${sortField}—— 表名/字段名无法参数化,必须白名单校验sortField值是否属于["id", "name", "created_at"] -
WHERE table_name = '${tableName}'—— 数据库对象名不能用#{},需严格限制输入范围或使用枚举映射 -
IN (${ids})—— 动态IN列表应改用<foreach></foreach>标签生成多个?占位符,而非拼接逗号分隔字符串
安全写法示例:
<select id="findUsers" resulttype="User">
SELECT * FROM user
WHERE deleted = 0
AND name LIKE #{namePattern}
<choose><when test="status != null">AND status = #{status}</when></choose></select>
输入验证不能替代参数化,但能堵住边缘漏洞
参数化解决的是“SQL语法层面”的注入,但业务层仍需校验:比如手机号字段传入 1'; DROP TABLE user; --,虽不会触发SQL注入,却可能造成日志污染、前端XSS或业务逻辑异常。
建议做法:
- 对ID类字段(如
userId)强制要求为正整数,用Long.parseLong()或正则"\d+"检查 - 对文本字段(如用户名、邮箱)用白名单正则,例如
^[a-zA-Z0-9_\u4e00-\u9fa5]{2,20}$ - 敏感操作(如删除、导出)必须二次确认+权限校验,不能仅靠前端隐藏按钮
- 过滤器(如Spring Boot的
@WebFilter)可拦截含UNION SELECT、EXEC(、@@version等关键词的请求,但仅作补充,不可依赖
真正容易被忽略的点是:ORM框架自动生成的SQL也可能出问题——Hibernate的原生SQL查询、MyBatis的 <script></script> 标签、JPA的 @Query(native=true),一旦用到字符串拼接,防护就失效了。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










