如何在动态SQL中安全实现Order By多字段排序避免注入?

雨枫大大_6763

雨枫大大_6763

2026-09-03

1030人浏览

原创

order by多字段不能参数化是sql语法硬限制,因数据库仅允许参数绑定“值”而非“标识符”,预编译不支持列名、排序方向等语法成分;多字段需逐个白名单校验,漏一即注入。

如何在动态sql中安全实现order by多字段排序避免注入?

ORDER BY 多字段为什么不能直接参数化

数据库引擎根本不允许把表名、列名、排序方向这些语法成分当参数传。你写 ORDER BY ?ORDER BY @col,SQL Server 会报 Incorrect syntax near '@',MySQL 报 You have an error in your SQL syntax。这不是 MyBatis 或 JDBC 的锅,是 SQL 标准和执行器的硬限制。多字段排序(比如 ORDER BY status, created_at DESC)只是让问题更明显——每个字段名、每个 ASC/DESC 都得单独校验,漏一个就等于开后门。

MyBatis-Plus 动态多字段排序的白名单落地方式

别信 QueryWrapper.orderByAsc("user_name") 能防注入,它底层仍是字符串拼接;也别用 ${sortFields} 直接接前端字符串。正确路径是:前端传类似 sort=name,created_at&order=asc,desc,后端拆成字段数组 + 方向数组,再逐个映射+校验。

  • 定义白名单枚举:SortColumnEnum.NAME("user_name")CREATED_AT("created_at"),不支持的字段名直接拒掉
  • 方向只接受 "asc""desc"(大小写统一转小写再比),其他值一律 fallback 到 "asc"
  • 字段数和方向数必须一致,不等就截断或报错,避免 name,age 对应 asc 导致第二个字段无方向
  • 最终用 LambdaQueryWrapper 构建时,循环调用 orderByAsc(Users::getName)orderByDesc(Users::getCreatedAt) —— 方法引用在编译期锁定列名,彻底避开字符串拼接

XML 中多字段 ${} 拼接的唯一安全边界

如果非要用 XML 写动态 SQL(比如要兼容旧逻辑或复杂表达式),${} 不是不能用,而是必须确保它只接收白名单校验后的结果。不要在校验前拼,更不要在校验后还做二次字符串处理。

闪控猫
闪控猫

一款AI开发辅助工具,主要用于多平台直播聚合中控系统,电商直播带货软件,适合需要提升相关任务效率的用户。

下载
  • 校验必须在进入 SQL 拼接前完成:先解析 sort=name,updated_at → 映射为 ["user_name", "updated_at"] → 检查每个是否在白名单中 → 全部通过才组装
  • 拼接时字段名加反引号(MySQL)或双引号(PostgreSQL):ORDER BY `#{col0}` ${dir0}, `#{col1}` ${dir1},防止字段名含空格或关键字
  • 禁止任何“兜底”操作:比如 REPLACE(${rawSort}, ';', '') 或正则删注释符,对 name; DROP TABLE-- 这类变体完全无效
  • 字段数建议设上限(如最多 3 个),超限直接 400,避免生成过长 SQL 或拖慢解析

PostgreSQL/SQL Server 存储过程中多字段动态排序的 CASE 替代法

存储过程里拼字符串最危险,也最容易被忽略。SQL Server 用 CASE 做分支,PostgreSQL 可用 NULLS FIRST/LAST 配合,核心都是把字段名“写死”,只让参数控制走向。

  • SQL Server 示例:ORDER BY CASE @sortField WHEN 'name' THEN name WHEN 'status' THEN status END * CASE @sortDir WHEN 1 THEN -1 ELSE 1 END —— 注意类型要一致,否则报转换错
  • PostgreSQL 更简洁:ORDER BY (CASE $1 WHEN 'name' THEN name WHEN 'price' THEN price END) $2 NULLS LAST,其中 $2'ASC''DESC' 参数
  • 字段名必须全部出现在 CASE 分支中,不能靠默认 ELSE 放行未知字段
  • 多字段时,每个字段独立写一套 CASE,不要试图共用一个分支变量

白名单不是加个配置项就完事,它得覆盖所有业务场景下的合法输入,包括别名、带下划线的物理列名、甚至 JSON 字段路径(如 data->>'score')。一旦漏掉一个真实使用的字段,开发就会绕过校验,或者临时打补丁拼字符串——那道防线就从内部瓦解了。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

3663

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

771

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

949

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

5421

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

2423

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

5420

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

7021

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

950

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

832

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133万人学习