0

sp_executesql をサポートするように SQL ステートメントを変換して安全にしようとしていますが、安全でない領域に遭遇しました。うまくいけば、皆さんはこれで私を助けてくれます. 問題を簡単に説明できるように、一時テーブルを作成しました。

問題は STEP #6 にあります。STEP #5 を使用できますが、これは安全ではなく、簡単にハッキングされる可能性があります。システムのパフォーマンスのために、キーワードを壊して何度も検索したくありません。

MS SQL 2008 メッセージ 4145 のエラー、レベル 15、状態 1、行 4 'ORDER' の近くで、条件が予想されるコンテキストで指定された非ブール型の式。

GO
/****** Object:  StoredProcedure [dbo].[ups_MultiWareHouse]    Script Date: 06/14/2012 09:12:38 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
create PROCEDURE ups_TestSearch(
@Keywords nvarchar(4000),
@SortColumns nvarchar(4000)
)
AS
--STEP #1 - Create Temp Table - Begin
    CREATE TABLE #TempTable 
    (
        ProductID uniqueidentifier,
        ProductName varchar(600),
        Price decimal(18,2),
        Active bit
    )

--STEP #2 - Insert couple records to search
    INSERT INTO #TempTable (ProductID,ProductName,Price,Active) VALUES(NEWID(),'Mouse','10.12','1')
    INSERT INTO #TempTable (ProductID,ProductName,Price,Active) VALUES(NEWID(),'Keyboard','20.45','1')
    INSERT INTO #TempTable (ProductID,ProductName,Price,Active) VALUES(NEWID(),'Monitor','150.87','0')--Disable this product

--STEP #3 - Display the current table data
        select 'STEP #3' as STEP,   * FROM #TempTable

--STEP #4 - SETTING UP sp_executesql to support parameter substitution
    --Set definition
    DECLARE @ParmDefinition nvarchar(4000);
    SET @ParmDefinition='
                        @Param1ProductName nvarchar(4000),
                        @Param2SortColumns nvarchar(4000)
                        '                   
    DECLARE @SQLString nvarchar(4000);

--STEP #5-  CONVERT THE @SQLString TO use @Keywords and @SortColumns
    --Run query for the below like this ups_TestSearch'ProductName=''Mouse'' OR ProductName=''Keyboard''', 'Price DESC, ProductName ASC'
    SET @SQLString = N'SELECT ''STEP #5'' as STEP, #TempTable.*  FROM #TempTable WHERE ('+@Keywords+') ORDER BY '+@SortColumns;--unsafe, open to hackers
    EXECUTE sp_executesql @SQLString, @ParmDefinition, @Param1ProductName = @Keywords, @Param2SortColumns=@SortColumns;

--STEP #6-  CONVERT THE @SQLString TO use @Keywords and @SortColumns
    --Run query for the below like this ups_TestSearch'ProductName=''Mouse'' OR ProductName=''Keyboard''', 'Price DESC, ProductName ASC'    
    SET @SQLString = N'SELECT ''STEP #6'' as STEP, #TempTable.*  FROM #TempTable WHERE (@Param1ProductName)  ORDER BY @SortColumns';--Safe but not working
    SELECT @SQLString AS SeeStatement
    EXECUTE sp_executesql @SQLString, @ParmDefinition, @Param1ProductName = @Keywords, @Param2SortColumns=@SortColumns;

--Drop temp table
DROP TABLE #TempTable
4

2 に答える 2

0

問題は、ステップ 5 でパラメーター置換を使用していないことだと思います。つまり、基本的に文字列連結によって SQL ステートメントを作成しています。sp_executesql を介して実行すると、実際には次のように実行できます。

EXECUTE sp_executesql @SqlString

手順 6 のコードは、パラメーター置換を実行しています。ただし、この場合、「通常の」SQL 式で許可されている場所でのみパラメーターを使用するように制限されています。たとえば、T-SQL でこれを行うことはできません。

DECLARE @Criteria NVARCHAR(500);
SET @Criteria = N' WHERE ProductName = ''Mouse'''
SELECT * FROM #MyTempTable + @Criteria

予想されるフィルターの複雑さに応じて、条件を一時テーブルに書き込み、一時テーブルへの結合を実行して、返される結果データを制限できる場合があります。頭のてっぺんから、おそらく呼び出しコードでそれを行わない限り、結果のデータをどのようにソートするのが最善かわかりませんか?

于 2012-06-14T15:46:45.093 に答える
0

エラー メッセージはWHERE、手順 6 の句が無効であることを示しており、句も無効ORDER BYです。これは、文字列をパラメーターとして渡し、sp_executesqlそれらを句全体として使用しようとしているためです。さらに、ステートメントはパラメータを参照して@SortColumnsいますが、パラメータに名前を付けたよう@Param2SortColumnsです。

一部の SQL サーバー MVP が書いたものを読んでください。

http://www.sommarskog.se/dynamic_sql.html

さらに要点: http://www.sommarskog.se/dyn-search.html

http://www.sqlmag.com/article/tsql3/parameterizing-result-order

パラメータとして句全体WHEREを渡しているため、これを機能させるためにプロシージャを変更する簡単な方法はわかりません。ORDER BY本当にすべきことは、proc を再設計することです。各WHERE基準を個別のパラメータとして に指定しups_TestSearchます。各WHEREパラメータをsp_executesql次のように初期 SQL ステートメントに再供給し、構造化します。

SET @SQLString = SELECT and JOIN portions of command
SET @SQLString = @SQLString + 'WHERE 1 = 1 '
  IF (@WhereParam1 IS NOT NULL)
    SET @SQLString = @SQLString + 'AND (SomeTable.SomeColumn = @WhereParam1) '
  IF (@WhereParam2 IS NOT NULL)
    SET @SQLString = @SQLString + 'AND (SomeTable.SomeColumn = @WhereParam2) '
  ...

必要に応じて、同じ構造を使用してステートメントに結合を追加できます。

構造は、ORDER BYこれがどの程度複雑になるか、および関連する可能性のあるすべての列を知っているかどうかによって異なります。比較的単純な場合は、次のようにステートメントとして記述するか、句CASEで推奨するように個々のパラメーターとして分割することができます。WHERE

ORDER BY
  CASE WHEN CHARINDEX(@SortColumns, 'SortCol1') > 0 THEN SortCol1 ELSE NULL END,
  CASE WHEN CHARINDEX(@SortColumns, 'SortCol2') > 0 THEN SortCol2 ELSE NULL END,
  ...

ここで行う最も簡単な方法は、DB ではなくアプリケーション レベルでソートすることかもしれませんが、複雑なORDER BY句をパラメーター化するのと同じくらい実行不可能な場合があります。

于 2012-06-14T17:24:52.650 に答える