动态 SQL 的 SQL 侧白名单是否存在问题?

Are there problems with SQL side white listing for Dynamic SQL?

我有一个应用程序,我想从我们的数据库中生成历史图表。 这些图表可以是许多不同的参数,它们存储在我们的 table 中,并带有耦合的日期时间。

存储过程将包含如下内容:

CREATE PROCEDURE [dbo].[getLog]
    -- Add the parameters for the stored procedure here

    @getIdEntity INT = 0 ,
    @columnName VARCHAR(100),
    @startDate DATETIME2,
    @endDate DATETIME2

AS
    SELECT logs.[DateTime], 
        logs.@column1 as Property
        from dbo.LogTable logs
    WHERE logs.[IdEntity] = @IdEntity AND logs.[DateTime] >= @startDate
    AND logs.[DateTime] <= @endDate 
    AND logs.column1 IS NOT NULL;'

这不起作用,无法将列作为参数插入。

答案当然是动态的 SQL,这显然会导致 SQL 注入问题。

程序变成:

ALTER PROCEDURE [dbo].[getLog]
    -- Add the parameters for the stored procedure here

    @getIdEntity INT = 0 ,
    @columnName VARCHAR(100),
    @startDate DATETIME2,
    @endDate DATETIME2

AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;
    -- Insert statements for procedure here



    DECLARE 
    @dynamicSql NVARCHAR(500),
    @timespan INT

    SET @dynamicSql = '
        SELECT [DateTime],  
        [' +@columnName+'] as Property from dbo.EntityTransactionLogEntry etl 
        WHERE etl.[IdEntity] = '+ CAST(@getIdEntity AS VARCHAR(10))
        + ' AND etl.[DateTime] >= '''+ (CONVERT (VARCHAR(50),@startDate,121)) +''''
        + ' AND etl.[DateTime] <= '''+ (CONVERT (VARCHAR(50),@endDate,121)) +''''
        + ' AND etl.[' +@columnName+'] IS NOT NULL;
    EXEC (@dynamicSql)'

这显然仍然容易受到 SQL 注入。

只是添加:

IF NOT EXISTS (SELECT * FROM 
            INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_NAME = 'EntityTransactionLogEntry'
            AND COLUMN_NAME = @columnName)
BEGIN
    PRINT  'Bad Input'
    RETURN
END

(我也限制了可查询的最大时间跨度,但我在这里并不担心) 在 Dynamic SQL 部分足以保护它免受注入之前? 它被设计为在提供了无效的列名时失败。

如果是,那么大概创建一个仅包含我同意查询的列名的视图将被允许限制可以使用的列?

我特别担心注射,但我认为我很安全,这只能从我们的 API.

获得

欢迎 Flippie

通常你可以做一些类似的事情

parameters..
.. paramterx varchar(100) = null,
paramtery varchar(100) = null

select *
from entitytransactionlog
where
  logs.[IdEntity] = @IdEntity AND logs.[DateTime] >= @startDate
  AND logs.[DateTime] <= @endDate 
  and (columnvalue = parameterx or parameterx is null)
  and (columnvalue2 = parametery or parametery is null)

所以 sp 被调用为

exec sp parameterx = 'value'

括号中的验证"OR"如果参数中的值未定义则让每个值

Is simply adding [a check in INFORMATION_SCHEMA] before the Dynamic SQL portion sufficient to protect this from injection?

根据定义,没有。发生的事情仍然是SQL注入。

从技术上讲,您要问的是 恶意 SQL 注入是否安全。

您的检查 INFORMATION_SCHEMA 是一种合理的保护。这是白名单的一种形式,这是我们必须使用的技术,用于不能被查询参数替换的东西。

如果 EntityTransactionLogEntry 中有一个列的名称可以 "break" 分隔标识符语法,你就会遇到麻烦,但我假设你可以控制自己的 table,你不会那样做的。

您应该将 INFORMATION_SCHEMA 查询限制为您自己的 TABLE_SCHEMA。由于您的查询当前已写入,如果 any table 中编目 I_S 具有该列名称,则可以满足。

此外,我不确定您为什么不在 IdEntity 和 DateTime 的条款中使用查询参数,其中值 可以 替换为查询参数。你应该这样做。