2011-12-19 8 views
5

これは簡単にここに挿入できます。なぜなら、このSQL文の中で@IDパラメータが実際には何でも入力できるからです。SQLインジェクションからSQL Serverストアドプロシージャを安全にする

私は、アプリケーションレベルではなく、このレベルでこの悪用を特に防ぐのが好きです。

CREATE PROCEDURE [dbo].[GetDataByID] 
@ID bigint, 
@Table varchar(150) 
AS 
BEGIN 

Declare @SQL Varchar(1000) 

SELECT @SQL = 'SELECT * FROM ' + @Table + ' WHERE ID = ' + CONVERT(varchar,@ID) 

SET NOCOUNT ON; 

EXEC(@sql) 
END 
+1

多くのことに影響を与えない小さなものですが、ここで問題となる '@ Table'パラメータはありません。 '@ID'は' bigint'なので、動的SQL文を作成する時点に達したときだけ数値にすることができます。 –

+0

私は両方とも.. –

答えて

9

チェックthis page、それは動的SQLへの素晴らしいガイドを持っており、あなたのケースでは、安全

それらを実行するためのオプションが、それはこのようにする必要があります:作成)

SELECT @SQL = N'SELECT * FROM ' + quotename(@Table) + N' WHERE ID = @xid' 
EXEC sp_executesql @SQL, N'@xid bigint', @ID 
+0

+1 Sommarskogにリンクします。 – Oded

+1

私は実際に私がStackOverflowで出会った人を知っている初めての+1です;) – Tao

+0

笑!こんにちはタオ! :) –

1

1 ID PKを持ち、文字列テーブル名を含む新しいテーブル
2)プロシージャで許可する有効なテーブルのみをすべて挿入する
3)このintを使用するストアド・プロシージャの入力パラメータ値(TableID)としてID PKを指定します。
4)プロシージャ内で、指定されたID PKから文字列値(表名)を検索するだけで、問合せ内のその参照文字列を連結することができます。 5)WHERE句は、あなたがintを渡すのでうまくいきます

0

私は動的SQLを避けることをお勧めします。次のような問題があります:

  • 明らか注射は
  • バイナリインジェクション攻撃は非常に賢くあり、大きなものさ
  • パフォーマンスをエスケープする伝統的な文字列をバイパスすることができシナリオ添付 - SQL Serverは上の実行計画を管理するために設計され動的に構築されるクエリよりも高速に実行されます。動的SQLを使用している場合は、ストアド・プロシージャをまったく使用することに実質的な利点はありません。複数のテーブルから選択するコードに柔軟性を持たせたい場合は、コードを簡単にするためにORMなどを考慮する必要があります。テーブルを動的に渡さなければならないと考えると、上記のような手続きには何の指摘もなく、別の解決策が最善の選択肢であると言っています。あなたがSQL(つまりORMなし)に対して書いているのであれば、別のprocsを生成するコードもより良い選択肢になります。

注:注:あなたは注入安全ではありません。切り捨て注入は依然として可能です。使用する前にhttp://msdn.microsoft.com/en-us/library/ms161953.aspxをお読みください。

+0

ご回答いただきありがとうございますが、QUOTENAMEに関する実用的なリンクを投稿できますか? –

+0

ここに何が起こったのかわからない:)今すぐ働くべきだ。 – Gats

0

一般的に私は動的SQLに対してアドバイスをしていますが、この場合は@Table変数に有効なテーブル名が含まれているかどうかを調べることでそれを取り除くことができます。

  • 質問は、スキーマ名やクロスdbクエリを許可する予定がある場合は、ここでdb(またはサーバー)から外に出たくないと思っていますが、別のスキーマ(AdventureWorksは、その使い方を示しています)
  • @Tableのビューも含める必要があります。
  • 見つかったオブジェクトに実際にID列があるかどうかをチェックし、そうでない場合は 'userfriendly'エラーがスローされたとします。しかし、オプションです。

QuoteName()を@tableの周りに置くだけでは、あなたをすべてから守ることはできません。優れた機能はありますが、完璧ではありません。 IMHOあなたの最善の策は@Table変数を解析し、その内容が有効かどうかを確認し、得られた部分に基づいて動的SQLを作成することです。 は私が

CREATE PROCEDURE [dbo].[GetDataByID] ( 
             @ID bigint, 
             @Table nvarchar(300) 
            ) 
AS 

DECLARE @sql nvarchar(max) 

DECLARE @server_name sysname, 
     @db_name  sysname, 
     @schema_name sysname, 
     @object_name sysname, 
     @schema_id int   

SELECT @server_name = ParseName(@Table, 4), 
     @db_name  = ParseName(@Table, 3), 
     @schema_name = ParseName(@Table, 2), 
     @object_name = ParseName(@Table, 1) 

IF ISNULL(@server_name, @@SERVERNAME) <> @@SERVERNAME 
    BEGIN 
     RaisError('Queries are restricted to this server only.', 16, 1) 
     Return(-1) 
    END 

IF ISNULL(@db_name, DB_Name()) <> DB_Name() 
    BEGIN 
     RaisError('Queries are restricted to this database only.', 16, 1) 
     Return(-1) 
    END 


IF @schema_name IS NULL 
    BEGIN 
     IF NOT EXISTS (SELECT * 
          FROM sys.objects 
         WHERE name = @object_name 
          AND type IN ('U', 'V')) 
      BEGIN 
       RaisError('Requested @Table not found. [%s]', 16, 1, @object_name) 
       Return(-1) 
      END 

     SELECT @sql = 'SELECT * FROM ' + QuoteName(@object_name) + ' WHERE ID = @ID' 
    END 
ELSE 
    BEGIN 

     SELECT @schema_id = Schema_id(@schema_name) 

     IF @schema_id IS NULL 
      BEGIN 
       RaisError('Unrecognized schema requested [%s].', 16, 1, @schema_name) 
       Return(-1) 
      END 

     IF NOT EXISTS (SELECT * 
          FROM sys.objects 
         WHERE name = @object_name 
          AND schema_id = @schema_id 
          AND type IN ('U', 'V')) 
      BEGIN 
       RaisError('Requested @Table not found. [%s].[%s]', 16, 1, @schema_name, @object_name) 
       Return(-1) 
      END 

     SELECT @sql = 'SELECT * FROM ' + QuoteName(@schema_name) + '.' + QuoteName(@object_name) + ' WHERE ID = @ID' 
    END 

EXEC sp_executesql @stmt = @sql, 
        @params = N'@ID bigint', 
        @ID  = @ID 

Return(0)  

スープラのコンパイル)=それは、このような単純なに見える何かをチェックするの多くを必要以上と驚くほどそこのほとんどをやって始まったが、私は「didnのようあなたはいくつかのバグをアイロンをする必要がある場合がありますすべてのコードパスを調べる限りはかなり進んでいます。

関連する問題