存储过程 SQL 注入检查

Stored procedure SQL Injection check

提问人:Steven Kuan 提问时间:10/24/2019 最后编辑:Dale KSteven Kuan 更新时间:10/25/2019 访问量:450

问:

我编写了以下用于查询数据库的存储过程。有人可以告诉我这个动态查询存储过程是否容易受到 SQL 注入攻击吗?

如果是,如何修改以下代码来防止SQL注入攻击?

第二个问题是在事业的最后,每次执行都需要吗?OPTION (RECOMPILE)WHERE

CREATE PROCEDURE DataMapMainQuery
    (@DataMapID VARCHAR(MAX),
     @DataMapIDName VARCHAR(MAX),
     @StartIndex INT,
     @MaximumRows INT,
     @sortExpression VARCHAR(MAX))
AS
BEGIN   
    DECLARE @FilteredTotalRows AS INT
    DECLARE @SqlString NVARCHAR(MAX)
    DECLARE @WhereString1 NVARCHAR(MAX)
    DECLARE @WhereString2 NVARCHAR(MAX)

    IF (@DataMapID IS NULL)
        SET @WhereString1 = ' AND (DataMapID LIKE ' + '''%%''' + ' OR NULL IS NULL)'
    ELSE
        SET @WhereString1 = ' AND (DataMapID LIKE ' + '''%' + @DataMapID + '%''' + ' OR ''' + @DataMapID + ''' IS NULL)'

    IF (@DataMapIDName IS NULL)
        SET @WhereString2 = ' AND (DataMapIDName LIKE ' + '''%%''' + ' OR NULL IS NULL)'
    ELSE
        SET @WhereString2 = ' AND (DataMapIDName LIKE ' + '''%' + @DataMapIDName + '%''' + ' OR ''' + @DataMapIDName + ''' IS NULL)'

    IF (@sortExpression IS NULL)
        SET @sortExpression = 'DataMapID'

    SELECT
        @FilteredTotalRows = COUNT(*) 
    FROM
        DataMapMain
    WHERE
        1 = 1
        AND (DataMapID LIKE '%' + @DataMapID + '%' OR @DataMapID IS NULL)
        AND (DataMapIDName LIKE '%' + @DataMapIDName + '%' OR @DataMapIDName IS NULL)

    IF (@FilteredTotalRows < @StartIndex + 1)
    BEGIN
        SET @SqlString = '
                SELECT 
                    DataMapID, DataMapIDName,
                    DataMapGroup, DataMapGroupRemark,
                    CONVERT(BIGINT, TimeStamp) AS TimeStamp
                FROM 
                    (SELECT
                         ROW_NUMBER() OVER (ORDER BY ' + @sortExpression + ') AS RowNumber,
                         DataMapID, DataMapIDName,
                         DataMapGroup, DataMapGroupRemark,
                         TimeStamp
                     FROM
                         DataMapMain
                     WHERE
                         1 = 1' 
                    + @WhereString1
                    + @WhereString2
                    + ') DataMapMain
                WHERE
                     RowNumber >= 1 
                     AND RowNumber < (1 + ' + CONVERT(NVARCHAR(10), @MaximumRows) + ') 
                OPTION (RECOMPILE)'
    END
    ELSE
    BEGIN
        SET @SqlString = '
                SELECT 
                    DataMapID
                    ,DataMapIDName
                    ,DataMapGroup
                    ,DataMapGroupRemark
                    ,CONVERT(bigint, TimeStamp) as TimeStamp
                FROM 
                     (
                     Select ROW_NUMBER() over (order by '  + @sortExpression + ') as RowNumber
                    ,DataMapID
                    ,DataMapIDName
                    ,DataMapGroup
                    ,DataMapGroupRemark
                    ,TimeStamp
                     From DataMapMain
                     WHERE
                        1 = 1'
                    + @WhereString1
                    + @WhereString2

                        + ') DataMapMain
                WHERE
                    RowNumber >= (' +  CONVERT(nvarchar(10),@StartIndex) + ' + 1) and RowNumber < (' + CONVERT(nvarchar(10),@StartIndex) + ' + 1 + ' + CONVERT(nvarchar(10),@MaximumRows) + ' )
                    OPTION (RECOMPILE)'
            END 
            PRINT @SqlString
            PRINT @FilteredTotalRows
        EXEC sp_executesql @SqlString
    END
sql-server t-sql 存储过程 sql 注入

评论

0赞 JB's 10/24/2019
Sql 参数将被视为字符串,转义字符将添加特殊字符
0赞 Zohar Peled 10/24/2019
您应该真正阅读 SQL Server 动态 SQL 的注意事项
0赞 Zohar Peled 10/24/2019
哦,你不需要选项(重新编译)。由于 SQL 是动态的,因此无论如何它每次都会重新编译。

答:

0赞 Ed Bangga 10/24/2019 #1

到目前为止,您是安全的,因为您在主 sql 查询中应用之前先构建它。我建议添加这些行来检查您的@DataMapID@DataMapNamesort expression, maxrows and start index

    IF (@sortExpression NOT IN ('ASC', 'DESC'))
    BEGIN
            RAISERROR('invalid order expression', 16,1);
            RETURN;
    END;


    IF (TRY_CAST(@StartIndex as int) = null or TRY_CAST(@MaximumRows as int) = null)
    BEGIN
            RAISERROR('invalid startindex or maximum rows', 16,1);
            RETURN;
    END;

评论

0赞 Steven Kuan 10/25/2019
我代码中的@sortExpression不仅仅是“ASC”或“DESC”,它还包括排序列名称,但您的建议提醒我检查参数,谢谢!
1赞 gotqn 10/24/2019 #2

只需与参数一起使用。生成动态 T-SQL 语句,但需要添加 value .然后像这样调用例程:sp_executesql@parameter_name

EXEC sp_executesql @sql
                  ,N'@parameter_name1 INT, @parameter_name2 VARCHAR(128), @parameter_name3 BIT'
                  ,@parameter_name1, @parameter_name2, @parameter_name3;
0赞 Esat Erkec 10/24/2019 #3

添加 OPTION(RECOMPILE) 提示可以为每次执行的查询执行重新构建新的执行计划。在某些情况下,它可以帮助提高性能。但是,重新编译操作会使用内存和 CPU 资源来生成新的执行计划。因此,如果您不确定性能的效果,则不会使用它

评论

0赞 Steven Kuan 10/25/2019
你是对的!我将删除 OPTION(RECOMPILE),谢谢!
0赞 Steven Kuan 10/25/2019
我不能点赞,我想这是因为我的声誉得分只有 8。我会尽快投赞成票。谢谢!
0赞 Steven Kuan 10/25/2019 #4

感谢您的所有帮助,我重写了下面的代码。如果不行,请告诉我。 谢谢大家!

CREATE PROCEDURE DataMapMainQuery
    (@DataMapID VARCHAR(MAX),
     @DataMapIDName VARCHAR(MAX),
     @StartIndex INT,
     @MaximumRows INT,
     @sortExpression VARCHAR(MAX))
AS
BEGIN   
    DECLARE @FilteredTotalRows AS INT
    DECLARE @SqlString NVARCHAR(MAX)
    DECLARE @params NVARCHAR(MAX);
    DECLARE @WhereString1 NVARCHAR(MAX)
    DECLARE @WhereString2 NVARCHAR(MAX)

    IF (@DataMapID IS NULL)
        SET @WhereString1 = ' AND (DataMapID LIKE ' + '''%%''' + ' OR NULL IS NULL)'
    ELSE
        SET @WhereString1 = ' AND (DataMapID LIKE ' + '''%' + @DataMapID + '%''' + ' OR ''' + @DataMapID + ''' IS NULL)'

    IF (@DataMapIDName IS NULL)
        SET @WhereString2 = ' AND (DataMapIDName LIKE ' + '''%%''' + ' OR NULL IS NULL)'
    ELSE
        SET @WhereString2 = ' AND (DataMapIDName LIKE ' + '''%' + @DataMapIDName + '%''' + ' OR ''' + @DataMapIDName + ''' IS NULL)'

    IF (@sortExpression IS NULL)
        SET @sortExpression = 'DataMapID'

    SELECT
        @FilteredTotalRows = COUNT(*) 
    FROM
        DataMapMain
    WHERE
        1 = 1
        AND (DataMapID LIKE '%' + @DataMapID + '%' OR @DataMapID IS NULL)
        AND (DataMapIDName LIKE '%' + @DataMapIDName + '%' OR @DataMapIDName IS NULL)

    IF (@FilteredTotalRows < @StartIndex + 1)
    BEGIN
        SET @SqlString = '
                SELECT 
                    DataMapID, DataMapIDName,
                    DataMapGroup, DataMapGroupRemark,
                    CONVERT(BIGINT, TimeStamp) AS TimeStamp
                FROM 
                    (SELECT
                         ROW_NUMBER() OVER (ORDER BY ' + @sortExpression + ') AS RowNumber,
                         DataMapID, DataMapIDName,
                         DataMapGroup, DataMapGroupRemark,
                         TimeStamp
                     FROM
                         DataMapMain
                     WHERE
                         1 = 1' 
                    + @WhereString1
                    + @WhereString2
                    + ') DataMapMain
                WHERE
                     RowNumber >= 1 
                     AND RowNumber < (1 + ' + CONVERT(NVARCHAR(10), @MaximumRows) + ')'
    END
    ELSE
    BEGIN
        SET @SqlString = '
                SELECT 
                    DataMapID
                    ,DataMapIDName
                    ,DataMapGroup
                    ,DataMapGroupRemark
                    ,CONVERT(bigint, TimeStamp) as TimeStamp
                FROM 
                     (
                     Select ROW_NUMBER() over (order by '  + @sortExpression + ') as RowNumber
                    ,DataMapID
                    ,DataMapIDName
                    ,DataMapGroup
                    ,DataMapGroupRemark
                    ,TimeStamp
                     From DataMapMain
                     WHERE
                        1 = 1'
                    + @WhereString1
                    + @WhereString2

                        + ') DataMapMain
                WHERE
                    RowNumber >= (' +  CONVERT(nvarchar(10),@StartIndex) + ' + 1) and RowNumber < (' + CONVERT(nvarchar(10),@StartIndex) + ' + 1 + ' + CONVERT(nvarchar(10),@MaximumRows) + ' )'
            END

    SET @params = '
        @DataMapID      VARCHAR(MAX)
        ,@DataMapIDName     VARCHAR(MAX)
        ,@StartIndex    INT
        ,@MaximumRows   INT
        ,@sortExpression VARCHAR(MAX)';

    EXEC sp_executesql 
        @SqlString
        ,@params
        ,@DataMapID
        ,@DataMapIDName
        ,@StartIndex
        ,@MaximumRows
        ,@sortExpression;
    END