我刚刚遇到了一件奇怪的事情...我们网站上的一些代码正在使用一个巨大的 SQL 语句,通过根据某些用户值进行一些搜索和替换来修改代码,然后将其传递给SQL Server 作为查询。
我认为这作为对存储过程的参数化查询会更清晰,以用户值作为参数,但是当我更仔细地观察时,我明白他们为什么这样做......它们是表选择不同程度地取决于这些用户值。
例如,在一种情况下,如果值为 (“FOO”、“BAR”),则查询最终将类似于“SELECT * FROM FOO_BAR”
有没有一种简单明了的方法可以做到这一点?我尝试的一切似乎都不优雅。
编辑:当然,我可以在存储过程中动态生成sql,并执行它(bleh),但那时我想知道我是否获得了任何东西。
编辑2:以某种智能方式重构表名称,比如说将它们全部放在一个表中,并以不同的名称作为新列,这将是解决所有这些问题的好方法,这几个人直接指出或暗示。遗憾的是,在这种情况下这不是一个选择。
最佳答案
首先,您应该永远在客户端应用程序上执行这样的 SQL 命令组合,这就是 SQL 注入(inject)。 (对于没有自己的权限的管理工具来说这是可以的,但对于共享使用的应用程序来说就不行了)。
其次,是的,对存储过程的参数化调用既干净又安全。
但是,由于您需要使用动态 SQL 来执行此操作,您仍然不希望在执行的查询的文本中包含传递的字符串。相反,您希望使用传递的字符串来查找应允许用户以这种方式查询的实际表的名称。
这是一个简单的例子:
CREATE PROC spCountAnyTableRows( @PassedTableName as NVarchar(255) ) AS
-- Counts the number of rows from any non-system Table, *SAFELY*
BEGIN
DECLARE @ActualTableName AS NVarchar(255)
SELECT @ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = @PassedTableName
DECLARE @sql AS NVARCHAR(MAX)
SELECT @sql = 'SELECT COUNT(*) FROM ' + @ActualTableName + ';'
EXEC(@SQL)
END
<小时/>
有些人问为什么这样更安全。希望小鲍比表可以让这一点更清楚: 0
<小时/>更多问题的答案:
单独使用 QUOTENAME 并不能保证安全。 MS 鼓励我们使用它,但他们并没有保证它不会被黑客欺骗。仅供引用,真正的安全在于保证。使用 QUOTENAME 进行表查找是另一个故事,它牢不可破。
QUOTENAME 对于本例来说并不是绝对必要的,仅对 INFORMATION_SCHEMA 进行查找翻译通常就足够了。 QUOTENAME 放在这里是因为从安全角度考虑,包含完整且正确的解决方案是一种良好的形式。这里的 QUOTENAME 实际上是在防止一个独特但类似的潜在问题,即潜在注入(inject)。
我应该注意到,您可以对动态列名称和 INFORMATION_SCHEMA.COLUMNS
表执行相同的操作。
您还可以通过使用参数化 SQL 查询来绕过对存储过程的需求(请参见此处: https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.parameters?view=netframework-4.8 )。但我认为存储过程为此类情况提供了更易于管理且不易出错的安全工具。
关于sql - 我应该如何将表名传递到存储过程中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1246760/