2012-03-08 3 views
0

他のシステムのSQL Server 2005データベースを照会する必要がある検索フォームがあります(ストアドプロシージャ/ファンクションを制御できないため)。.NetとSQL Server 2005:リストに対してクエリを実行するときの注入を防止する

一般的に注入を防止するために、私のコードは次のようになります:

SqlCommand cmd = new SqlCommand("SELECT * FROM myTable WHERE Id = @Id", conn); 
cmd.Parameters.AddWithValue("@Id", 1234); 

このシナリオは少し異なっている、という点では、フォームのように動作するように値のカンマ区切りリストを可能にすることを要求されていますよくだから私はこのような何かをするでしょうか:

string ids = "1234, 1235, 1236"; 
SqlCommand cmd = new SqlCommand("SELECT * FROM myTable WHERE Id IN (" + ids + ")", conn); 

安全な方法で、1つのクエリで?

答えて

0

これは私が思い付く最高の解決策でした。誰もが任意の脆弱性を見ているなら、私に教えてください:

string idList = "1234, 1235, 1236"; 

XElement ids = new XElement("ds"); 
foreach (string s in idList.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(id => id.Trim())) 
    ids.Add(new XElement("d", s)); 

SqlCommand cmd = new SqlCommand("SELECT * FROM myTable WHERE Id IN (SELECT T.ids.value('.', 'int') FROM @Ids.nodes('/ds/d') AS T(ids))", conn); 
cmd.Parameters.Add(new SqlParameter("@Ids", ids.ToString(SaveOptions.DisableFormatting)) { SqlDbType = SqlDbType.Xml }); 
2

SQLにリストを渡して型チェックを行う方法はたくさんあります。このアドホックSQLではなくストアドプロシージャを使用する場合は、リストを文字列パラメータとして渡して、プロシージャ内で解析するだけです。リストに非整数があれば、単にエラーになります。例えば

この機能:

CREATE FUNCTION [dbo].[SplitInts] 
(
    @List  VARCHAR(MAX), 
    @Delimiter CHAR(1) 
) 
RETURNS TABLE 
AS 
    RETURN (SELECT Item FROM (SELECT Item = x.i.value('(./text())[1]', 'int') FROM 
      (SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(@List, @Delimiter, '</i><i>') 
       + '</i>').query('.')) AS a CROSS APPLY [XML].nodes('i') AS x(i) 
     ) AS y WHERE Item IS NOT NULL 
    ); 
GO 

は次のように呼び出すことができます:

SELECT Item FROM dbo.SplitInts('1234, 1235, 1236', ','); 

結果:

Item 
---- 
1234 
1235 
1236 

あなたはまったく文字列を使用しようとすると、それは爆弾:

SELECT Item FROM dbo.SplitInts('1234; DROP TABLE bobbytables;', ','); 

結果: のnvarchar値「1234変換するとき

メッセージ245、レベル16、状態1、行1
、変換に失敗しました。 DROP TABLE bobbytables; 'データ型intに変換します。

だから、代わりにそのスプリット機能で、あなたのストアドプロシージャは、このように書くことができます

CREATE PROCEDURE dbo.GetMyTable 
    @List VARCHAR(MAX) 
AS 
BEGIN 
    SET NOCOUNT ON; 

    SELECT t.col1, t.col2 --, ... 
     FROM dbo.myTable AS t 
     INNER JOIN dbo.SplitInts(@List, ',') AS i 
     ON t.Id = i.Item; 
END 
GO 

を、これは気にせず、厳密に型指定された文字列パラメータ@Listと.NETから呼び出すことができあなたはStoredProcedure commandTypeを使用して適切な呼び出しにパラメータを渡し、自分自身でEXEC ...文字列を構築しようとしない限り、SQLインジェクションは何でも可能です。

SQL Server 2008ではさらにステップを進めて、セットのデータをDataTableなどのストアドプロシージャパラメータに設定できるように、テーブル値パラメータ(TVP)を使用できます。

+0

こんにちはアーロン - ポストから、私の限界の一つは、そうでない場合、私はこの – John

+0

ウェルに似た何かをするだろう、私は彼らのストアドプロシージャや関数を制御することはできませんですうまくいけば、あなたは文字列としてパラメータを供給するだけでは不十分なので、他の誰かが賢明なことをしている - SQL Serverには配列がない。おそらく。NETを使用すると、文字列をループし、すべての整数であることを確認してから、それらをまとめてクエリを構築することができます。クライアントは注射予防に興味がありますか?おそらく、ストアドプロシージャを作成してそれを防ぐことができるようにする方がよりオープンになるでしょう。 –

+0

私は 'String.Split'(http://msdn.microsoft.com/en-us/library/b873y76a.aspx)と' Int.TryParse'(http://msdn.microsoft.com/)の単純な組み合わせと思います。 en-us/library/f02979c7.aspx).NETでこれを行うことができます。 – Bridge

関連する問題