首页/安全/漏洞与攻击面速查/排序与表名参数的处理方式
Web 漏洞原理与防护55 条

排序与表名参数的处理方式

ORDER BY 字段、表名、列名等位置无法使用参数占位符,容易被拼接入 SQL;正确做法是白名单映射:应用只接受预设键值,映射到固定 SQL 片段。

漏洞与攻击面速查安全更新于 2026-10-13

为什么这里不能参数化

ORDER BY 的字段名、表名、列名属于 SQL 的结构位置,数据库不接受参数占位符,很多开发者于是退回字符串拼接,形成排序注入。正确做法是白名单映射:应用只接受预设键值,再把键映射到固定的 SQL 片段,白名单之外一律回退默认值。Java、Python、PHP、Go 各语言的处理方式相同。

基本信息

风险位置ORDER BY、GROUP BY、表名、列名、排序方向
成因SQL 结构位置不能用占位符,退回拼接
防护键值白名单映射 + 默认值回退
禁止做法关键字黑名单过滤、手工转义
适用平台所有使用参数化查询但仍拼接结构片段的后端

典型使用场景

  • 列表页排序:?sort=created_at&order=desc 这类参数最常被忽略
  • 导出接口:导出时的字段与排序参数往往比页面接口校验更松
  • 动态报表:用户自选统计列与分组维度
  • 搜索接口:多字段模糊匹配时拼接排序表达式
  • 分页与方向控制:asc/desc 方向值同样是注入点

白名单映射示例

白名单映射示例
SORT_WHITELIST = {
    "name": "name",              # 前端键 -> 数据库列
    "created_at": "created_at",
    "score": "score",
}
ORDER_WHITELIST = {"asc": "ASC", "desc": "DESC"}

col = SORT_WHITELIST.get(request.args.get("sort"), "created_at")   # 未知键回退默认
way = ORDER_WHITELIST.get(request.args.get("order", "desc"), "DESC")
sql = f"SELECT id, name FROM items ORDER BY {col} {way} LIMIT %s OFFSET %s"
cursor.execute(sql, (page_size, offset))   # 值仍走参数绑定

常见位置与处理对照

位置可用占位符正确做法
WHERE 条件值可以参数绑定
ORDER BY 字段名不可以白名单映射到固定列名
排序方向 asc/desc不可以枚举校验,非法即回退默认
表名或列名不可以白名单映射,禁止直接拼接
LIMIT/OFFSET多数驱动支持仍建议整数强校验后再绑定
白名单之外一律回退默认值,不要回显用户输入的错误提示:把非法键返回 400 并附上允许的键列表,对定位问题更有帮助。
LIMIT 与 OFFSET 在多数数据库驱动中可以参数化,但排序方向和字段名不能;遇到驱动限制时,用整数强校验放在绑定之前,而不是退回字符串拼接。

易错点

  • 对 ORDER BY 位置直接使用占位符会报语法错误,开发者因此退回拼接:应改用白名单
  • 只过滤引号和分号:布尔盲注与时间盲注常用 order by 后的表达式,不依赖引号闭合
  • 对排序方向字段不做校验:asc/desc 位置同样可被替换为子查询
  • 白名单键直接当列名使用:键与列名不一致时应在服务端做映射,而不是信任前端传来的字段名

数据来源与参考

  • OWASP SQL Injection Prevention Cheat Sheet(ORDER BY 场景)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌