如何在Java Spring Boot中安全实现动态排序功能防范SQL注入风险
问题根源
JDBC的PreparedStatement的参数占位符?仅支持值参数的替换,无法用于SQL标识符(列名、表名)、SQL关键字(ASC/DESC)的占位。你传入字符串的时候JDBC会自动给值加单引号,就变成了你遇到的ORDER BY 'col1' 'ASC'的非法语法。
正确实现方案
核心思路是先对白名单校验用户传入的排序参数,再动态拼接合法的ORDER BY子句,校验通过后再拼接就不会有SQL注入风险。
实现步骤
- 提前定义允许排序的字段白名单,拒绝所有不在白名单内的排序字段请求
- 校验排序方向仅允许
ASC/DESC两种值,非法值直接抛出参数异常或使用默认值 - 校验通过后将合法参数拼接入SQL,再执行查询
代码示例
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import java.util.List; import java.util.Set; public class QueryDemo { // 定义允许排序的字段白名单,和数据库表字段一一对应 private static final Set<String> ALLOWED_ORDER_COLUMNS = Set.of("col1", "col2"); // 合法的排序方向 private static final Set<String> ALLOWED_DIRECTIONS = Set.of("ASC", "DESC"); static <T> List<T> myQuery(JdbcTemplate jdbc, RowMapper<T> mapper, String orderBy, String direction) { // 校验排序字段合法性 if (!ALLOWED_ORDER_COLUMNS.contains(orderBy)) { throw new IllegalArgumentException("非法的排序字段:" + orderBy); } // 校验排序方向合法性,统一转大写避免大小写问题 String upperDir = direction.toUpperCase(); if (!ALLOWED_DIRECTIONS.contains(upperDir)) { throw new IllegalArgumentException("非法的排序方向:" + direction); } // 校验通过后拼接SQL String sql = String.format("SELECT * FROM myTable ORDER BY %s %s", orderBy, upperDir); return jdbc.query(sql, mapper); } }
Spring原生简化方案
如果使用Spring Data模块,可以直接用org.springframework.data.domain.Sort类封装排序逻辑,Spring会自动完成参数合法性校验和SQL拼接:
// 接口层接收Sort参数时,Spring Web可以自动转换请求参数为Sort对象 static <T> List<T> myQuery(JdbcTemplate jdbc, RowMapper<T> mapper, Sort sort) { // 从Sort对象获取合法的ORDER BY子句 String orderClause = sort.stream() .map(order -> order.getProperty() + " " + order.getDirection()) .reduce((a, b) -> a + ", " + b) .orElse("col1 ASC"); // 兜底默认排序规则 String sql = "SELECT * FROM myTable ORDER BY " + orderClause; return jdbc.query(sql, mapper); }
注意:使用Sort时同样建议追加白名单校验,避免传入非法字段。
内容的提问来源于stack exchange,提问作者Stormcloud
相关产品推荐
相关产品推荐

