【发布时间】:2023-04-03 19:45:01
【问题描述】:
在观看 Troy Hunt 的精彩 course on SQLi 时,我注意到他最终使用此策略来查看表格是否具有特定列:
select * from TableA order by (select top 1 some_column from TableB) desc
这个表达式将被 SQL Server 执行,但是它对 order by 子句有什么作用呢?我已经看到表达式与 order by before 一起使用(case when then else end),但我真的很想了解 SQL 如何在没有任何错误的情况下处理前面的查询......
编辑:提供更多信息,因为我最初的帖子似乎不够清楚:
- 我知道这不是通过 SQLi 获取表或列名的最佳策略(这不是我要问的)
- 我不想知道如何防止这种情况发生(我已经知道该怎么做)
- 我知道按常数值排序没有意义(尽管它允许您运行这些类型的“布尔查询”)
- 我真正想知道的是它为什么有效。
所以,回到文档,order by 子句需要一个 order_by_expression,它被描述为:
指定对查询结果集进行排序的列或表达式。排序列可以指定为名称或列别名,或表示列在选择列表中的位置的非负整数。
根据docs,表达式为:
是 SQL Server 数据库引擎评估以获得单个数据值的符号和运算符的组合。简单表达式可以是单个常量、变量、列或标量函数。运算符可用于将两个或多个简单表达式连接成一个复杂表达式。
正如@SMor 所演示的,如果您用简单的select 'A' 替换选择表达式的顺序,则查询会运行:
select * from TableA order by (select 'A') desc
但这不起作用:
select * from TableA order by 'A' desc
那么,问题是:为什么select 'A' 在 order by 子句中被 SQL Server 接受?它不也产生一个常数吗?由于常量是一个表达式,并且考虑到order by 子句的定义,它不应该在两种情况下都抛出错误吗?
谢谢。
【问题讨论】:
-
“这个策略来查看一个表是否有特定的列” - 你这是什么意思?
-
这被用作回答是或否的注入示例。如果没有表或没有列,则会抛出异常(这在 sql 异常未传播到客户端时很有用)。当 tje 列和表确实存在时,sql 返回记录,尽管我不确定它们是如何排序的......你可以在 ssms 和 aee 上测试这个查询确实被执行(即使通过 select 的顺序返回一个字符串.. .
-
看起来是一个非常糟糕的策略:如果列名为
1); drop TableA; --会发生什么,它仍然会导致注入。防止注射的唯一方法是一开始就不要注射。换句话说,您应该始终完全控制 SQL,如果需要动态 SQL,则使用诸如sys.columns和sys.tables之类的 DMV 来构建查询 -
再说一次,这不是我要问的......我真正想知道的是为什么查询运行时没有任何错误以及它用于排序。谢谢。
-
它不使用任何东西进行排序。它在优化过程中识别出它实际上是一个常数并被优化出来。 “在 ORDER BY 列表中遇到了常量表达式”是相当保守的,并且只发生在非常简单的情况下。
ORDER BY (SELECT ...)有时非常有用。例如与ROW_NUMBER结合使用,以任意顺序为每一行指定一个唯一编号,无需排序]
标签: sql sql-server sql-order-by