jdbcTemplate防止注入写法
前一期写过拼接查询
https://blog.csdn.net/qq_44749121/article/details/148084689
但是会涉及到注入风险
所幸这一期给一个改进写法
在 Spring 框架中使用 JdbcTemplate 时,可以通过以下方式有效防止 SQL 注入:
1. 使用预编译语句(PreparedStatement)
这是最核心的防注入方式,所有动态参数都应该通过参数绑定传递
String sql = "INSERT INTO user (name, age) VALUES (?, ?)";
jdbcTemplate.update(sql, user.getName(), user.getAge());
2. 使用 NamedParameterJdbcTemplate
命名参数方式更易维护且支持重复参数
// 需要先注入 NamedParameterJdbcTemplate
@Autowired
private NamedParameterJdbcTemplate namedJdbcTemplate;public User getUser(String name) {String sql = "SELECT * FROM user WHERE name = :name";Map<String, Object> params = new HashMap<>();params.put("name", name);return namedJdbcTemplate.queryForObject(sql, params, new UserRowMapper());
}
3. 查询操作示例
普通查询
String sql = "SELECT * FROM products WHERE price > ? AND category = ?";
List<Product> products = jdbcTemplate.query(sql, new Object[]{minPrice, category}, // 参数数组new BeanPropertyRowMapper<>(Product.class)
);
IN 查询
String sql = "SELECT * FROM users WHERE id IN (:ids)";
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("ids", Arrays.asList(1, 2, 3));List<User> users = namedJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<>(User.class)
);
更新操作示例
String sql = "UPDATE orders SET status = ? WHERE order_id = ?";
jdbcTemplate.update(sql, newStatus, orderId);
4、动态条件查询
StringBuilder sql = new StringBuilder("SELECT * FROM products WHERE 1=1 ");
List<Object> params = new ArrayList<>();if (priceMin != null) {sql.append("AND price >= ? ");params.add(priceMin);
}if (category != null) {sql.append("AND category = ? ");params.add(category);
}jdbcTemplate.query(sql.toString(), params.toArray(), new BeanPropertyRowMapper<>.(Standard.class));
5、特别注意不安全写法
// ❌ 危险!字符串拼接直接嵌入用户输入
String unsafeSql = "SELECT * FROM users WHERE name = '" + userInput + "'";
jdbcTemplate.query(unsafeSql, ...);// ❌ 错误使用 LIKE
String wrongLikeSql = "SELECT * FROM users WHERE name LIKE '%" + userInput + "%'";
防御原理
参数绑定:通过 PreparedStatement 将参数值与 SQL 语句分离
自动转义:JDBC 驱动会自动处理特殊字符(如单引号转义为 ‘’)
类型安全:自动处理数据类型转换(如 Date → java.sql.Date)
最佳实践
禁用字符串拼接:永远不要将用户输入直接拼接到 SQL 中
白名单校验:对于排序字段等必须动态拼接的场景,使用白名单校验
日志监控:启用 SQL 日志,监控异常查询模式
最小权限原则:数据库账号分配最低必要权限
只要严格使用参数化查询(? 或 :paramName),即可有效防御 99% 的 SQL 注入攻击。